kotlin-内联类

Kotlin 1.5 宣布了一个重磅特性 value class,这是一个非常实用的特性,提高代码的可读性同时,还可以提高性能,因为编译器会对它进行更深层次的优化,减少对象的创建。

内联类的 inline 修饰符已弃用,该用value关键修饰,然后在类上添加@jvmInline

  • 内联类是对某一个类型的包装
  • 内联类是类似于Java装箱类型的一种类型
  • 编译器会尽可能使用被包装的类型进行优化
1
value class Password(private val s:String)

内联类必须含有唯一的一个属性在主构造函数,在运行时,将使用这个唯一属性来表示内联类的实例。

1
2
3
//不存在Password 类的真实实例对象
// 在运行时,‘securePassword’ 仅仅包含`String`
val securePassword =Password("Don`t try this in production)

这就是内联类的主要特性,它灵感来源inline这个名称;类的数据被内敛到该类是使用的地方(类似于内联函数中的代码被内联到该函数调用的地方)。

成员

内联类支持普通类的一些功能,特别是,内联类可以声明属性与函数以及init代码块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@JvmInline
value class Name(private val s: String) {
init {
require(s.isNotEmpty())
}

val length: Int
get() = s.length

fun greet() {
println("Hello, $s")
}
}

fun main() {
val name = Name("Kotlin")//name在编译期间为String
name.greet()// greet 方法会作为一个静态方法被调用
println(name.length) //属性的get 方法会作为一个静态方法调用
println(name)//最终被装箱成Name
}

main使用方法在编译成对应的Java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static final void main() {
//抹去Name,调用静态方法直接返回`String`
String name = Name.constructor-impl("Kotlin");
//调用greet-impl静态方法
Name.greet-impl(name);
//调用getLength-impl静态方法
int var1 = Name.getLength-impl(name);
boolean var2 = false;
System.out.println(var1);
Name var3 = Name.box-impl(name);//String最后被装箱成 Name
var2 = false;
System.out.println(var3);
}

模拟枚举类

在移动端开发的过程中出于对内存考虑,大家都尽量避免使用枚举类。所以在java中经常使用@StringDef@IntDef,如果不清楚可自行查阅使用。但是在kotlin中虽然能使用,但是在IDE失去的了提示效果,就无法限定输入类型。具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.SOURCE)
@StringDef(SOUTH, NORTH)
annotation class FilterType {
companion object {
const val NORTH = "NORTH"
const val SOUTH = "SOUTH"
}
}

fun setFileType(@FilterType type: String) {
println("type====$type")
}

fun main() {
setFileType("MMMM") //虽然用@FilterType修饰,但是IDE不会提示
}

如果遇到这个问题,可以考虑用内联类代替,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
inline class Color(val value: UInt) {
companion object {
val Red = Color(0xFFFF0000u)
val Green = Color(0xFF00FF00u)
val Blue = Color(0xFF0000FFu)
}

fun values() = arrayOf(Red, Green, Blue)

val name: String
get() = when (this) {
Red -> "Red"
Green -> "Green"
Blue -> "Blue"
else -> throw IllegalArgumentException()
}
}
fun setColor(color: Color){
println(color.name)
}
fun main() {
setColor(Color.BLUE)
}

setColor中限定了类型为color,直接使用Color伴生对象现成的定义