Kotlin Lateinit通讯Java

und*_*oid 2 java android kotlin

您好,当我使用Kotlin对Android进行编程时,我已经lateinit在代码中看到了。java中的等效项是什么?如何将该代码从Kotlin更改为Java?

public class MyTest {
    lateinit var subject: TestSubject
}
Run Code Online (Sandbox Code Playgroud)

zsm*_*b13 5

lateinit 在Kotlin中,您可以在变量上设置非空类型,这些变量在创建包含它们的类时无法初始化。

以您的示例为例,如果您不使用lateinit,则必须使它为subject可空值,因为必须使用一个值对其进行初始化。

public class MyTest {
    var subject: TestSubject? = null
}
Run Code Online (Sandbox Code Playgroud)

这将迫使您每次使用时都要进行空检查,这很丑陋,因此您可以将其标记为lateinit。


在Java中,您实际上没有这个问题,因为所有内容都是可为空的,并且声明未初始化的字段没什么特别的:

public class JavaTest {
    TestSubject subject;
}
Run Code Online (Sandbox Code Playgroud)

初始化subject为null,因此实际上与非lateinitKotlin示例等效。

lateinitKotlin版本与Java版本之间的唯一真正区别是,当您尝试访问Kotlin中未初始化的属性时,会得到一个更具体的异常,即a UninitializedPropertyAccessException,这将使调试比查找a的原因更容易。通用的NullPointerException。


如果您确实想要这种稍微不同的行为,则可以将Java属性包装在某种包装器中,但是我认为这样做不值得在语法上开销。一种非常基本的方法(例如,不是线程安全的)是:

具有用于属性的通用包装器类:

public class Property<T> {

    private T value = null;

    public T get() {
        if (value == null)
            throw new UninitializedPropertyAccessException("Property has not been initialized");
        return value;
    }

    public void set(T value) {
        if (value == null)
            throw new IllegalArgumentException("Value can't be null");
        this.value = value;
    }

}
Run Code Online (Sandbox Code Playgroud)

在您的课程中使用此包装器:

public class JavaTest {
    Property<TestSubject> subject = new Property<>();
}
Run Code Online (Sandbox Code Playgroud)

然后,这种用法将给您未初始化的异常:

JavaTest test = new JavaTest();
test.subject.get();
Run Code Online (Sandbox Code Playgroud)

并且这将运行良好:

JavaTest test = new JavaTest();
test.subject.set(new TestSubject());
test.subject.get();
Run Code Online (Sandbox Code Playgroud)

编辑:这与lateinitKotlin中的工作原理非常相似,如果将示例的字节码反编译为Java,则会得到以下结果:

public final class MyTest {
   @NotNull
   public TestSubject subject;

   @NotNull
   public final TestSubject getSubject() {
      TestSubject var10000 = this.subject;
      if(this.subject == null) {
         Intrinsics.throwUninitializedPropertyAccessException("subject");
      }
      return var10000;
   }

   public final void setSubject(@NotNull TestSubject var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.subject = var1;
   }
}
Run Code Online (Sandbox Code Playgroud)

基本上,编译器将用于检查属性访问的代码放在类本身内(+使用了一些辅助方法),而不是使用包装器,后者效率更高。