kotlin1.8.20 内联类 value class 更新

143 阅读2分钟

Kotlin 1.8.20 解除了对在内联类中使用带主体的二级构造函数的限制。

1. 通过关键词value+@JvmInline声明了一个内联类

//内联类
//1.4.30 解除了 init 代码块的限制,
//1.5.0 由inline class => value + @jvmInline
//1.8.20 解除了二级构造函数的限制
@JvmInline
value class Person(private val fullName: String):PersonX {
    init {
        check(fullName.isNotBlank()) {

        }
    }
    constructor(name: String, lastName: String) : this("$name--$lastName") {
        check(lastName.isNotBlank()){

        }
    }
}

interface PersonX{

}

2. 内联类的限制

内联类没有被当成其他类型使用。 若不满足这个条件,内联就会失败,此时会发生装箱,内联类被当成一个包装类被构建

  • 普通类具备的功能,内联类几乎都具备: 成员变量/方法 & 实现接口
  • 内联类在保证类型安全的同时能做到了零性能损耗
interface I

@JvmInline
value class Foo(val i: Int) : I

fun asInline(f: Foo) {}
fun <T> asGeneric(x: T) {}
fun asInterface(i: I) {}
fun asNullable(i: Foo?) {}

fun <T> id(x: T): T = x

fun main() {
    val f = Foo(42)

    asInline(f)    // unboxed: used as Foo itself
    asGeneric(f)   // boxed: used as generic type T
    asInterface(f) // boxed: used as type I
    asNullable(f)  // boxed: used as Foo?, which is different from Foo

    // below, 'f' first is boxed (while being passed to 'id') and then unboxed (when returned from 'id')
    // In the end, 'c' contains unboxed representation (just '42'), as 'f'
    //'f'首先被装箱(当被传递给'id'时),然后被拆箱(当从'id'返回时)
    val c = id(f)
}

反编译

int f = Foo.constructor-impl(1);
Foo.geet-impl(f);
int c = ((Foo)id(Foo.box-impl(f))).unbox-impl();
asInline-TNYJG3E(f);

3.它通常用于约束语义,并以零性能损耗的方式通过编译器保证类型安全

/**
 *
 * @param second 秒
 */
fun printTime(second:Second){
   println("当前输入秒 :$second")
}
/**
 *
 * @param minute 分钟
 */
fun printTime(minute:Minute){
    println("当前输入分钟 :$minute")
}


@JvmInline
value class Second(val second: Long)


data class Minute(val minute: Long)

fun main(){
  // 当 kotlin 编译成 java 后,内联类型不会被创建,而是将其成员内联到调用处
   printTime(Second(1))
  // 构建新的包装对象(在堆中分配内存,并在栈中指向这块内存)
   printTime(Minute(1))
}

image.png