[英]Null checks not inserted for reified type when param is non-nullable
TL; DR生成类型的函数在生成代码时是否应考虑类型参数可为空性吗?
测试用例
考虑以下Kotlin代码; 这两种方法之间的唯一差别是所结合的类型是否可为空( 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; }
这是Kotlin 1.1.4。
预期行为
我希望它们的行为等效-类型化,因此已知T
的实际值不可为空,因此应在return
语句之前的函数内部应用null检查。
观察到的行为
这两种情况以不同的方式失败:
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;
[...]
因此,看来空检查的插入是基于绑定的类型,而不是实际的类型。
完全正确,这就是应该的工作方式!
根据实际的通用类型,JVM函数不能具有不同的字节码,因此相同的实现必须满足所有可能的结果。
内联不会影响这种情况,因为它遵循与普通函数相同的规则。 它是通过这种方式设计的,因此开发人员不会感到惊讶。
问题是否在于函数是否内联。
从Kotlin的文档中 :
Java中的任何引用都可能为null,这使得Kotlin对来自Java的对象的严格的null安全性要求不切实际。 Java声明的类型在Kotlin中被特别对待,称为平台类型。 对此类类型放宽了空检查,因此它们的安全保证与Java中的相同
在Java端使用@Nullable
批注,您可以强制kotlin检查类型是否可以为null(使用@NotNull
)
@Nullable
public static <T> T unsafeMethod() { return null; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.