如何使用Kotlin KClass属性simpleName生成null

时间:2019-07-27 06:24:56

标签: kotlin

在Kotlin 1.3.41上KClass.simpleName的Common,JS,JVM和Native规范是:

  

在源代码中声明的类的简单名称,或者   如果该类没有名称,则返回null(例如,如果它是一个匿名名称)   对象文字)。

生成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

2 个答案:

答案 0 :(得分:1)

我对您的代码做了一些更改:

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
    })
}

为什么名称2的值是

现在让我们看看它的字节码。
这是start函数的字节码的一部分。如您所见,它实现了Function0,并且它具有一个invoke的{​​{1}}方法。

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$1Lambda。 如果您在像这样的主函数之间添加了一个虚拟方法:

Function0

那么您的班级名称将是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 }) } 那就是为什么它是2的答案

我应该如何更改代码以使名称的值为空?

您可以使用3代替qualifiedName。这一定是文档中的错误,只需忽略括号中的部分,例如“如果它是一个匿名对象文字”。 这就是医生对qualifiedName的评价:

该类的全限定点名,如果该类是本地或匿名对象的类,则为null。

它像它所说的那样工作。

simpleName

答案 1 :(得分:0)

从Kotlin中的simpleName中获取null的唯一方法是引用Java构建的类,或者使用类定义从字面上覆盖simpleName。默认情况下,Kotlin在JVM上生成的类始终具有定义的simpleName属性。