我正在查看为您的代码生成的JVM字节码.SamTest1
和SamTest2
看起来几乎相同(除了一些内部事物的名称),这很有意义,因为在JVM方面,val
与相同类型的0参数fun
没有什么不同.
public interface SamTest1 {
public boolean method1(@NotNull String var1);
public String other();
public static final class DefaultImpls {
public static String other(SamTest1 this_) {
return "test";
}
}
}
public interface SamTest2 {
public boolean method1(@NotNull String var1);
public String getOther();
public static final class DefaultImpls {
public static String getOther(SamTest1 this_) {
return "test";
}
}
}
当我们看到你的main
分时,令人兴奋的部分就来了.清理一些工件,看起来
static final class sam1$1 implements SamTest1 {
public static final sam1$1 INSTANCE = new sam1$1();
public final boolean method1(String it) {
return true;
}
public String other() {
return SamTest1.DefaultImpls.other(this);
}
}
public static final void main() {
SamTest1 sam12 = sam1$1.INSTANCE;
System.out.println(sam12.other());
SamTest2 sam2 = samKt::main$lambda$0;
System.out.println(sam2.getOther());
}
private static final boolean main$lambda$0(String it) {
return true;
}
因此,据我所知,Kotlin认识到SamTest1
有两个方法,因此(就Java而言)不是SAM接口,因此它创建了一个新类来表示匿名实例.该方法的默认值在匿名类中传递(正如在Kotlin中应该发生的那样),一切正常.
但看起来Kotlin thinks SamTest2
与Java的SAM接口机制兼容,只是向其传递了一个方法samKt::main$lambda$0
,希望JVM端的SAM机制能够综合构建对象.如果实际上只有一个抽象方法,那么这would可以很好地工作,但是JVM端有两个:method1
和getOther
,因此后者在调用时得到AbstractMethodError
.
我很想在这方面被证明是错误的,但我认为这是一个Kotlin bug.它应该 for each 生成合成类.我在bug追踪器上找不到任何类似的问题,但我认为编译器的行为在这里是不正确的.
注意:我使用CFR将JVM字节码反编译回Java.我删除了许多空判断、元数据注释和类型转换,以使本文更加简洁.