声明站点差异可能导致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>
? extends String
Source extends String>
Source extends String>
是一个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
分配给MutableList
variables,则会发现无法添加任何内容,因为根本无法在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 ”参数。