Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Kotlin KClass属性simpleName生成null_Kotlin - Fatal编程技术网

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

如何使用Kotlin KClass属性simpleName生成null,kotlin,Kotlin,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 ob

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

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

我稍微更改了您的代码:

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
方法,该方法采用
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
的类,它扩展了
Lambda
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
    })
}
那么您的类的名称将是
3
这就是为什么它是2的答案

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

您可以使用
qualifiedName
而不是
simpleName
。这一定是文档中的一个错误,忽略括号中的“如果,例如,它是匿名对象文字”部分。 以下是医生对qualifiedName的看法:

类的完全限定点分隔名称,如果类是本地的或匿名对象的类,则为null

正如它所说的那样

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

也许这是您的测试框架的一些奇怪行为。当我将粘贴的代码复制到
fun main()
中时,它会打印
null
——当我将它粘贴到类函数中并从main方法运行它时,我能够重现该问题。Kotlin 1.3.41无法使用Kotlin 1.3.41进行复制。你能提供一份详细的报告吗?您使用的是什么版本的Kotlin?您的构建环境是什么?你在使用什么测试框架?我至少有一个JS报告null和JVM报告2的报告。使用OpenJDK 12.0.1、Windows 10和Gradle 4.10/Gradle 5.5.1克隆存储库后,HmmmmStill无法复制。执行
clean build
成功完成。测试报告显示9个成功测试和0个失败。