您好,当我使用Kotlin编程Android时,我在代码中看到了lateinit
。 java中的等价物是什么?如何将此代码从Kotlin更改为Java?
public class MyTest {
lateinit var subject: TestSubject
}
答案 0 :(得分:5)
lateinit
,因此您可以在变量上创建不可为空的类型,这些变量在创建包含它们的类时无法初始化。
使用您的示例,如果您未使用lateinit
,则必须使subject
为空,因为必须使用值进行初始化。
public class MyTest {
var subject: TestSubject? = null
}
这会强制您在每次使用时都进行空检查,这很难看,因此您可以将其标记为lateinit
。
在Java中,你没有真正遇到这个问题,因为一切都可以为空,并且声明一个未初始化的字段并不特别:
public class JavaTest {
TestSubject subject;
}
这会将subject
初始化为null
,因此它实际上等同于非lateinit
Kotlin示例。
Kotlin中的lateinit
版本与Java版本之间唯一真正的区别是,当您尝试访问Kotlin中的未初始化属性时,您会获得更具体的异常,即UninitializedPropertyAccessException
,使调试更容易,而不是寻找通用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;
}
}
在你的课程中使用这个包装器:
public class JavaTest {
Property<TestSubject> subject = new Property<>();
}
然后这个用法会给你未初始化的异常:
JavaTest test = new JavaTest();
test.subject.get();
这一个可以正常运行:
JavaTest test = new JavaTest();
test.subject.set(new TestSubject());
test.subject.get();
编辑:这与lateinit
在Kotlin中的工作方式非常相似,如果您将示例的字节码反编译为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;
}
}
基本上,编译器将用于检查属性访问的代码放在类本身内(+使用一些辅助方法)而不是使用包装器,这样更有效。
答案 1 :(得分:0)
Java中没有这样的属性会延迟属性的初始化。但我认为Kotlin和Java中的行为非常相似。
这是我的两分钱:
在Kotlin中,在初始化之前访问lateinit属性会抛出一个特殊的异常,它可以清楚地识别被访问的属性以及它尚未初始化的事实。 (参考:https://kotlinlang.org/docs/reference/properties.html)。
在Java中,还抛出NullPointerException(NPE),表示正在访问的属性为Null。
唯一的区别可能是,NPE是运行时异常。
答案 2 :(得分:0)
有许多examples here。就您而言:
public class MyTest {
lateinit var subject: TestSubject
}
它将编译为以下Java代码:
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
public final class MyTest {
@NotNull public TestSubject subject;
@NotNull
public final TestSubject getSubject() {
TestSubject testSubject = this.subject;
if (testSubject == null) {
Intrinsics.throwUninitializedPropertyAccessException((String) "subject");
}
return testSubject;
}
public final void setSubject(@NotNull TestSubject testSubject) {
Intrinsics.checkParameterIsNotNull((Object) testSubject, (String) "<set-?>");
this.subject = testSubject;
}
}