声明站点差异可能导致ClassCastException

Kotlin介绍了在这里描述的声明网站的变化。

generics参数的out / in关键字在某些情况下可能导致ClassCastException。 我的程序如下所示。

fun main(args: Array) { var l: List = mutableListOf("string") demo(l) println("======") for (s in l) { println(s) } } fun demo(strs: List) { val objects: List = strs // This is OK, since T is an out-parameter if (objects is MutableList) { val obs: MutableList = objects as MutableList obs.add(TextView()) } } 

输出:

 Exception in thread "main" java.lang.ClassCastException: com.kotlin.demo.clzz.TextView cannot be cast to java.lang.String at com.kotlin.demo.clzz.Declaration_Site_VarianceKt.main(Declaration-Site-Variance.kt:14) ====== adn 

推荐使用关键字的方式吗? 为什么?

您的代码可以在没有任何警告的情况下进行编译,这是因为声明网站方差仅在Kotlin中可用。

这与Java的使用地点差异形成对比,types用法中的通配符使types协变。

例如,2个Soruce接口在Kotlin中使用声明站点差异 :

 interface Source interface Source 

这两个Source接口将被生成到Java中的相同源代码中,如下所示:

 // v---`T extends Object` rather than `? extends T` public interface Source{ /**/ } 

这是因为通配符? 被用作types参数而不是Java中的types参数。 Source中的Source是一个types参数 , 在Source ? extends String Source Source是一个types参数

因此,如果使用types投影将objects强制为List ,则编译器将报告UNCHECKED_CAST警告,例如:

 fun demo(strs: List) { // v--- makes it explicitly by using out type proejction val objects: List = strs if (objects is MutableList) { // v--- an UNCHECKED_CAST warning reported val obs: MutableList = objects as MutableList obs.add(TextView()) } } 

换句话说,你不能将一个List MutableList一个MutableList 。 否则,你会得到一个编译错误。 例如:

 fun demo(strs: List) { val objects: List = strs if (objects is MutableList) { // v--- ? extends Object //ERROR: can't assign MutableList to Mutable // v ^--- Object val obs: MutableList = objects obs.add(TextView()) } } 

如果objects分配给MutableListvariables,则会发现无法添加任何内容,因为根本无法在Kotlin中创建Nothing 。 例如:

 fun demo(strs: List) { val objects: List = strs if (objects is MutableList) { // v--- down-casting to `MutableList` val obs: MutableList = objects // v---ERROR: can't be instantiated obs.add(Nothing()) } } 

:在推荐的练习中使用关键字的方式是?

Java描述了如何使用通配符 ,它也适用于Kotlin。

一个“ in ”variables,注意这里的“ in ”是? extends T ? extends T和Kotlin相同:

一个“in”variables将数据提供给代码。 想象一下有两个参数的复制方法: copy(src, dest)src参数提供要复制的数据,所以它是“ in ”参数。

一个“ out ”variables,在这里记下“ out ”是? super T ? super T ,与Kotlin相同:

out ”variables保存用于其他地方的数据。 在复制示例中, copy(src, dest)dest参数接受数据,所以它是“ out ”参数。