为什么SamTest2接口在访问other属性时抛出一个AbstractMethodError?接口中提供了默认实现,因此我假设在main方法中创建的匿名实例将正常工作。这是一个错误的假设吗?
fun interface SamTest1 {
fun method1(value: String): Boolean
fun other(): String = "test"
}
fun interface SamTest2 {
fun method1(value: String): Boolean
val other: String
get() = "test"
}
fun main() {
val sam1 = SamTest1 { true }
println(sam1.other()) // test
val sam2 = SamTest2 { true }
println(sam2.other) // AbstractMethodError
}发布于 2022-06-24 01:55:31
我正在查看为您的代码生成的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似乎认为SamTest2与Java的SAM接口机制是兼容的,并且简单地传递给它一个方法samKt::main$lambda$0,希望JVM端的SAM机制能够综合地构造对象。如果实际上有一个抽象方法,但是JVM端有两个:method1和getOther,所以后者在调用时会得到AbstractMethodError,这会很好。
我很想在这件事上被证明是错的,但我认为这是一个Kotlin的错误。它应该为每个人生成合成类。我在bug跟踪器上找不到类似的问题,但是我认为编译器的行为在这里是不正确的。
注意:我使用CFR将JVM字节码反编译回Java。我删除了许多空检查、元数据注释和类型转换,以使文章简洁。
https://stackoverflow.com/questions/72737899
复制相似问题