变形泛型-Kotlin 中的 out 和 in关键字理解

首先有两个概念,协变和逆变

协变就是T所在位置可以由T的子类替代。就是
逆变是就是T所在位置都可以由T的父类替代。

这个东西很绕,他们都是变形(variance)的一种表现形式,编程语言都需要考虑这个性质,可以看下百度百科

先记住上面两句总结,再看一些例子就会加深一定的理解了。

我们先定义一个类,里面有一个函数

class Collection1 {
    fun  addAll(items: Collection1) {
		
    }
}

这里编译报错了,提示变形(variance)只能是类或者接口的参数类型。所以这里是函数的类型报错了,可见这东西只能用来定义接口和类的type。

我们再次定义一个函数,想法是仿写一个使用率极高的Collection类的addAll方法。我们第一次很可能是这样定义的。

class Collection1 {
    fun addAll(items: Collection1) {
		//具体实现。。。
    }
}

乍一看好像没什么,泛型支持我们传入各种类型,然后addAll就可以相加了,但我们测试一下

fun test(c1: Collection1, c2: Collection1) {
    c1.addAll(c2)//编译报错
}

结果返现编译报错了!这就很神奇了,第一个列表都可以接受Any类型的,讲道理,接受Int类型是当然没有问题的事情,因为我们Any类型的列表传入任何类型都是可以的。但是我们定义的addAll却报错说type mismatched: request Collection1 found Collection1,感觉这个编译器有点蠢对吧,原因后面再说。

此时就需要out来登场了,out E代表什么,回顾下上面的两句话,所有E可以使用的地方,他的子view都可以替换之,改一下代码。

class Collection1 {
    fun addAll(items: Collection1) {
		//具体实现。。。
    }
}

fun test(c1: Collection1, c2: Collection1) {
    c1.addAll(c2)//编译通过
}

果然这次可以随便addAll()了。我们看下java Collection类的实现,发现是,也就是说就相当于java的

这是一种用法在函数中定义类的类型,还有一种直接再类中定义的用法,直接上代码。

open class SuperClass 

open class TClass : SuperClass() 

class NetworkState()
//class NetworkState

fun test(){
	var father = NetworkState()
	var son = NetworkState()
	father = son
}

主要看father = son赋值这行,不用run代码就可以猜到,如果像注释那样写没有out T,这一行是一定会报错的。而具体作用比如这里定义的NetworkState,代表网络状态,他会有一些比如error,loading之类的sub class。每个子view的定义的泛型一定是不一样的,最上层可能是Any,下面的比如loading子类可能是个枚举,error子类可能是个字符串,为了方便操作,定义成out 是有必要的。

in就是父View,刚好相反,就不举例了

你可能感兴趣的:(android)