2

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

我正在尝试编写简单的测试,它将在 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 值没有被比较,而是实际的内联类(应该在运行时展开)?

4

1 回答 1

6

您可能想要做的是val name = nameInlineClass.value,但我会尝试解释错误。

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

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

这意味着只要您不明确引用包装对象或其类型,值就不会被装箱。我们可以通过检查字节码来检查它(为了可读性而反编译回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仅检查nullofvaluebox-impl创建包装器对象的静态方法。

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

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

于 2019-05-25T22:53:07.927 回答