JUnit测试中的Kotlin内联类

时间:2019-05-25 21:22:11

标签: kotlin junit kotlin-experimental kotlin-inline-class

我试图理解内联类的概念-它们是在运行时内联的单一属性的简单对象包装。 这意味着该类的实际初始化不是在运行时发生的

我试图编写简单的测试,该测试将在JUnit测试期间直接显示我的上述解释,如下所示:

companion object {
   private const val NAME = "JACK"
}

inline class NameInlineClass(val value: String)

@Test
fun unwrapping() {
    val nameInlineClass = NameInlineClass(NAME)
    val name = nameInlineClass
    assertEquals(name, NAME)
}

不幸的是,该测试失败了,这使我想到一个问题,为什么在assertEquals()期间不比较实际的未包装的String值,而是在比较实际的内联类(在运行时应对其进行包装)?

1 个答案:

答案 0 :(得分:5)

您可能想做的是val name = nameInlineClass.value,但我将尽力解释该错误。

请参阅文档中的Representation(包括代码示例):

  

在生成的代码中,Kotlin编译器为每个内联代码保留一个包装器   类。内联类实例可以在运行时表示为   包装器或作为基础类型。这类似于Int的方式   表示为原始int或包装Integer。

这意味着只要您不显式引用包装对象或其类型,就不会将value装箱。我们可以通过检查字节码(将其反编译为Java以提高可读性)进行检查:

// kotlin source
fun unwrapping() {
    val nameInlineClass = NameInlineClass(NAME)
    val name = nameInlineClass  // this line gets dropped by compiler by the way
    assertEquals(name, NAME)
}

// java representation of bytecode
public final void unwrapping() {
   String nameInlineClass = NameInlineClass.constructor-impl("JACK");
   Assert.assertEquals(NameInlineClass.box-impl(nameInlineClass), "JACK");
}

我不会粘贴整个生成的NameInlineClass主体,但是constructor-impl是静态方法,仅检查null中的value,并且box-impl创建包装对象。

您可以看到nameInlineClass确实是String-这意味着内联有效,没有分配额外的对象。

仅当引用nameInlineClass而不是nameInlineClass.value时,编译器才确定该对象需要表示形式,并使用包装器NameInlineClass类将值“装箱”。