Kotlin 1.3.41 上针对 Common、JS、JVM 和 Native 的 KClass.simpleName 的规范是:



生成 null 似乎很简单:获取从匿名对象文字生成的 KClass 的 simpleName。下面的代码是一个失败的尝试:

interface Human { fun think(): String }

@Test fun `when finding the name of an anonymous object verify the name is null`() {
    fun start(man: Human) = println(man.think())

    start(object: Human {
        val name = this::class.simpleName
        override fun think() = "Thinking really hard! Name is: $name" // name == 2
    })
}

我的期望是名称应该是 null 。为什么名称为 2 的值?我应该如何更改代码以使 name 的值为 null

最佳答案

我稍微改变了你的代码:

interface Human { fun think(): String }

fun main() {

    fun start(man: Human) = println(man.think())

    start(object: Human {
        val name = this::class.java.simpleName
        override fun think() = "Thinking really hard! Name is: $name" // name == 2
    })
}

现在让我们看看这个字节码。
这是 start 函数的字节码的一部分。如您所见,它实现了 Function0 并且它有一个 invoke 方法,它采用 Human
final class com/example/customview/TestKt$main$1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function1 {


  // access flags 0x1041
  public synthetic bridge invoke(Ljava/lang/Object;)Ljava/lang/Object;
    ALOAD 0
    ALOAD 1
    CHECKCAST com/example/customview/Human
    INVOKEVIRTUAL com/example/customview/TestKt$main$1.invoke (Lcom/example/customview/Human;)V
    GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
    ARETURN
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x11
  public final invoke(Lcom/example/customview/Human;)V

   ....

这是匿名对象字节码的一部分,你可以看到它实现了 Human :
public final class com/example/customview/TestKt$main$2 implements com/example/customview/Human {

  OUTERCLASS com/example/customview/TestKt main ()V

  // access flags 0x12
  private final Ljava/lang/String; name

   .....

您可以从字节码中看到您的匿名类的名称实际上是 TestKt$main$2 。因为编译器会自动为您的文件生成一个类 TestKt 和另一个主函数类 TestKt$Main 。然后对于每个函数或匿名类,将生成另一个类,并按顺序命名它们。例如,这里的函数 start 有一个名为 TestKt$main$1 的类,它扩展了 LambdaFunction0
如果您在主函数中添加一个虚拟方法,如下所示:
fun main() {

    fun start(man: Human) = println(man.think())

    fun nothing() = {}

    start(object: Human {
        val name = this::class.java.simpleName
        override fun think() = "Thinking really hard! Name is: $name" // name == 3 this time
    })
}
那么你的类(class)名称将是 3这就是为什么它是 2 的答案

您可以使用 qualifiedName 而不是 simpleName 。这一定是文档中的错误,只需忽略括号中的部分,即“例如,如果它是匿名对象文字”。
这是文档中关于qualifiedName 的说明:

它像它所说的那样工作。
start(object: Human {
        val name = this::class.qualifiedName
        override fun think() = "Thinking really hard! Name is: $name" // name == null
    })

关于kotlin - 如何使用 Kotlin KClass 属性 simpleName 生成空值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57229715/

10-17 01:42