TL; DR在生成代码时,具有特定类型的函数是否应考虑类型参数的可空性?当参数不可为空时,为空化类型插入的空检查
测试用例
考虑以下科特林代码;这两种方法之间的唯一区别是类型绑定是否可以为空(Any?
)或不可以(Any
)。
@Test
fun testNonNullableBound() {
val x: Int = nonNullableBound()
}
@Test
fun testNullableBound() {
val x: Int = nullableBound()
}
private inline fun <reified T : Any> nonNullableBound(): T {
return unsafeMethod()
}
private inline fun <reified T : Any?> nullableBound(): T {
return unsafeMethod()
}
其中unsafeMethod
颠覆由在Java中所定义的类型的系统:
public static <T> T unsafeMethod() { return null; }
这是科特林1.1.4。
预期的行为
我期望这些表现等效 - 类型被物化,所以T
实际值被称为是不可为空,所以空校验应该在里面要应用功能在return
声明之前。
观察到的行为
两种情况下未能以不同的方式:
testNonNullableBound
行为与预期(由于失败对unsafeMethod()
返回值空校验)。testNullableBound
的行为并不像预期的那样 - 在执行x
分配时,它无法通过NPE执行。
因此,看起来插入的空检查是基于绑定的类型,而不是实际的类型。
分析
仅供参考,相关的字节码如下。请注意在testNonNullableBound
中添加的空检查。
testNonNullableBound
public final testNonNullableBound()V
@Lorg/junit/Test;()
[...]
L1
LINENUMBER 28 L1
INVOKESTATIC JavaStuff.unsafeMethod()Ljava/lang/Object;
DUP
LDC "unsafeMethod()"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
[...]
testNullableBound
public final testNullableBound()V
@Lorg/junit/Test;()
[...]
L1
LINENUMBER 27 L1
INVOKESTATIC JavaStuff.unsafeMethod()Ljava/lang/Object;
[...]
'空检查应该在函数内部要应用的回报statement.' 之前为什么你在做这样的假设? 您首先调用'unsafeMethod',然后检查它的可空性, – crgarridos
@crgarridos - 因为这就是非泛型情景中发生的情况(我假设泛化类型与此类似)。 –