前言
英词成群,非舞文弄墨。固知义足矣,译徒增负也。何以弃译知义,初篇答之。
正文
刚才复习这个知识点,中网、外网上都说得很模糊。并且这个特性在很多种语言中都有,我便总结一下。为尽可能照顾广大读者,用 Java 和 Kotlin 写了示例。示例很简单,如果某些语言特性不知道的话自己猜想一下便可以了,你猜的基本都是对的。
初衷
先从初衷讲起,我认为所有教学都该这样。
先列出三个 class,A 为 B的 superclass,B 为 C 的 superclass。( superclass 指父类,subclass 指子类)
class A{
int a = 0;
}
class B extends A {
int b = 1;
}
class C extends B {
int c = 2;
}
对于这样一个方法
void siteTest(List list){...}
如果存在一个参数,其类型为 List
Covariance
先用 wildcard (通配符) 在 Java 中类似实现,如下图。
如上,将类型为 List
如果在设计 List 时就一并实现的话,便是 covariance,如下
//interface 换成 class 也是可以的
interface List extends T>{}
//如果再限制 T 为 A 的 subclass,便是
interface List extends T extends A>{}
这样在方法 outSiteTest 中将 List extends B> 写为 List 就可以了。当然这只是为了举例说明,Java 的 class 或 interface 并不支持这样设计。不过很多其他语言都是支持的,如果用 Kotlin 来写的话便是这样:
interface List//或者 interface List
一般其他语言也都会在 covariance 中采用 out,这样设计是为了帮你更好理解所限制的使用范围。这时 IDE 会限制在 List 的子类中,全局 T 型变量只能为 private,对于非 private 的方法,T 只能出现在其括号外部(out)。试想一下,这样是不是就限制 T 型变量为只读了。
上述只是为了举例,Kotlin 中的 List 并没有这样设计。
此外,如果安全隐患可被自己手动排除呢。比如在写库的时候,自己明确知道会传进来哪些参数,可以使用哪些参数。在图中的例子里,cs 经 outSiteTest 使用后,如果在其他地方不对 cs 那个位置上的 element(元素) 取 c,是不是就安全了。Kotlin 为此提供了解决方法,对确保安全的参数不再限制,只要在其类型 T 前加一个注解 UnsafeVariance 就可以了,如下
class OutSite(var value: @UnsafeVariance T)
此时 value 为 private,但方法 getValue,setValue 均为 public。此外在方法中单独声明也是可以的,但这样就不能用 @UnsafeVariance 来解除限制了,如下:
fun outSiteTest(v:InSite){}
每种语言的解决方法不太一样,也可能并不支持解决,就不一一介绍了。
Contravariance
先用 wildcard 在 Java 中类似实现,如下图。
此时 IDE 会在 inSiteTest 中对 list 限制为只写,排除安全隐患。在其他语言中实现 contravariance 类比之前的 covariance,把 out 改为 in 即可,以限制 T 只能出现在 public 的方法括号内部(in),内含的全局 T 型变量同样只能为 private。
至此,已经把 covariance 和 contravariance 介绍完毕,相信你已经领悟了。
不定期更新
另有三个微信公众号,前者针对整个计算机领域,后两者针对安卓领域。公众号可以根据需要分开关注,更新得也会快一些,欢迎浏览。
愿意打赏可以扫码,多谢。



