为什么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
}

推荐答案

我正在查看为您的代码生成的JVM字节码.SamTest1SamTest2看起来几乎相同(除了一些内部事物的名称),这很有意义,因为在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端有两个:method1getOther,因此后者在调用时得到AbstractMethodError.

我很想在这方面被证明是错误的,但我认为这是一个Kotlin bug.它应该 for each 生成合成类.我在bug追踪器上找不到任何类似的问题,但我认为编译器的行为在这里是不正确的.


注意:我使用CFR将JVM字节码反编译回Java.我删除了许多空判断、元数据注释和类型转换,以使本文更加简洁.

Kotlin相关问答推荐

如何在使用Kotlin Coroutines时检测和记录何时出现背压

如何在Jetpack Compose中从领域查询中读取数据?

KTOR';S函数`staticResources`在Kotlin本机目标上不可用

collectAsState 未从存储库接收更改

扩展属性委托给实例属性

为什么使用 return instance ?: synchronized(this) { instance ?: PreferenceParameterState(context) } 时无法获得单例?

init中的NPE抽象函数变量

具有泛型类型的 Kotlin 密封接口不会为其子类型推断约束

测试协程和线程之间的差异,我在kotlin中使用线程时无法得到OOM错误

使用 Compose for Desktop Bundle 文件

为什么 KFunction2 在 Kotlin 中不是可表示类型?

如何在 Android 的 Fragment 中使用 setUserVisibleHint

在 SplashActivity 中显示的 Firebase 应用内消息.如何在 MainActivity 中显示它?

Kotlin 代码是如何编译成原生代码的?

Kotlin 无法找到或加载主类

如何从 Java 中隐藏 Kotlin 的 lateinit var 支持字段?

无法在 kotlin android 中以编程方式禁用 EditText

为什么 Dialog 没有 NavController [Missing]?

Intellij 显示 build.gradle.kts 中的每一行都是红色的

如何在 kotlin 中创建重复对象数组?