1、lateinit语法及其使用
lateinit用于延迟属性初始化的,语法如下所示:
lateinit var 变量名 : 非基本类型
lateinit 它只能用于对可变、非空、非基本数据类型
对应lateinit变量,可以使用::变量名.isLateinit判断属性是否已初始化,如果使用未初始化的lateinit变量,会抛出未初始化异常
使用如下所示:
class TestLateInit {
lateinit var a : A
fun main() {
a = A()
if (::a.isLateinit) {
print("a = $a")
}
}
}
class A () {
}
2、lateinit原理
基于1中的示例我们进行反编译查看已字节码,通过字节码剖析其原理,反编译命令为:javap -c -v -p TestLateInit.class:
Classfile /E:/project/MyApps/TCanvas/app/build/tmp/kotlin-classes/debug/com/wyx/tcanvas/test/delegate/TestLateInit.class
//省略.....
{
//成员变量a
public com.wyx.tcanvas.test.delegate.A a;
//省略.....
//构造函数
public com.wyx.tcanvas.test.delegate.TestLateInit();
//省略.....
Code:
stack=1, locals=1, args_size=1
//0-4: 调用父类即Object的init方法
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
//省略.....
//获取成员变量a的方法getA()
public final com.wyx.tcanvas.test.delegate.A getA();
//省略.....
Code:
stack=1, locals=2, args_size=1
// 0-10:判断成员变量是否为空,如果不为空,则返回成员变量a
0: aload_0
1: getfield #17 // Field a:Lcom/wyx/tcanvas/test/delegate/A;
4: astore_1
5: aload_1
6: ifnull 11
9: aload_1
10: areturn
//11-17:成员变量a为空,则抛出未初始化异常throwUninitializedPropertyAccessException
11: ldc #18 // String a
13: invokestatic #24 // Method kotlin/jvm/internal/Intrinsics.throwUninitializedPropertyAccessException:(Ljava/lang/String;)V
16: aconst_null
17: areturn
//省略.....
//设置成员变量a的方法setA()
public final void setA(com.wyx.tcanvas.test.delegate.A);
descriptor: (Lcom/wyx/tcanvas/test/delegate/A;)V
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
//0-11:判断方法参数为空,则抛出异常,否则赋值给成员变量a
0: aload_1
1: ldc #30 // String <set-?>
3: invokestatic #34 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_0
7: aload_1
8: putfield #17 // Field a:Lcom/wyx/tcanvas/test/delegate/A;
11: return
//省略.....
public final void main();
//省略.....
}
//省略.....
通过反编译TestLateInit字节码可以知道lateinit的原理其实是:
- 自动生成get和set方法
- get方法会判断变量是否为空,如果为空则抛出未初始化异常,如果不为空则返回变量
- set方法普通的var 变量一样
3、总结
lateinit延迟属性的初始化是用过get中判断是否为空,为空则抛出异常的实现原理。针对会抛出异常的问题可以使用isLateinit判断变量是否已初始化来解决