kotlin—lateinit及其实现原理

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."":()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 
         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判断变量是否已初始化来解决

你可能感兴趣的:(kotlin—lateinit及其实现原理)