速晓covariance, contravariance (协变、逆变)

本文探讨了Java和Kotlin中协变(Covariance)与逆变(Contravariance)的概念,通过示例解释了这两种特性在类型安全和泛型使用中的作用。文章指出,协变允许更具体的类型作为父类型的替代,而逆变则在方法参数中支持更广泛的类型。作者还提到了Kotlin的UnsafeVariance注解,用于在消除安全隐患的同时保持灵活性。
摘要由CSDN通过智能技术生成

 前言

        英词成群,非舞文弄墨。固知义足矣,译徒增负也。何以弃译知义,顶篇答之。

正文

        刚才复习这个知识点,中网、外网上都说得很模糊。并且这个特性在很多种语言中都有,我便总结一下。为尽可能照顾广大读者,用 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<B> list){...}

如果存在一个参数,其类型为 List<C> 或者 List<A>, 它是传递不到 siteTest 这个方法中的。因为在 siteTest 中使用该参数时存在安全隐患(见下文),IDE(开发工具) 便禁止了。但如果 IDE 针对这种情况在写代码时加一些限制以确保安全,不就提高很多效率了吗,此即设计 covariance, contravariance的初衷。

Covariance

先用 wildcard (通配符)  在 Java 中类似实现,如下图。

如上,将类型为 List<C> 的 cs 传递给方法 outSiteTest,IDE 会自动对 list 限制为只读,这样便杜绝了安全隐患。

        如果在设计 List 时就一并实现的话,便是 covariance,如下

//interface 换成 class 也是可以的
interface List<? extends T>{}
//如果再限制 T 为 A 的 subclass,便是
interface List<? extends T extends A>{}

这样在方法 outSiteTest 中将 List<? extends B> 写为 List<B> 就可以了。当然这只是为了举例说明,Java 的 class 或 interface 并不支持这样设计。不过很多其他语言都是支持的,如果用 Kotlin 来写的话便是这样:

interface List<out T>
//或者
interface List<out T : A>

一般其他语言也都会在 covariance 中采用 out,这样设计是为了帮你更好理解所限制的使用范围。如下所示,这时 IDE 会限制在 List 的子类中,全局 T 型变量只能为 private,对于非 private 的方法,T 只能出现在其括号外部(out)。如此,T 型变量的只读是不是就实现了。

    

        此外,如果安全隐患可被自己手动排除呢。比如在写库的时候,自己明确知道会传进来哪些参数,可以使用哪些参数。在图中的例子里,cs 经 outSiteTest 使用后,如果在其他地方不对 cs 那个位置上的 element(元素) 取 c,是不是就安全了。Kotlin 为此提供了解决方法,对确保安全的参数不再限制,只要在其类型 T 前加一个注解 UnsafeVariance 就可以了,如下

class OutSite <out T>(var value: @UnsafeVariance T)

此时 value 为 private,但方法 getValue,setValue 均为 public。此外在方法中单独声明也是可以的,但这样就不能用 @UnsafeVariance 来解除限制了,如下:

fun outSiteTest(v:InSite<out B>){}

每种语言的解决方法不太一样,也可能并不支持解决,就不一一介绍了。
 

Contravariance

        先用 wildcard  在 Java 中类似实现,如下图。

此时 IDE 会在 inSiteTest 中对 list 限制为只写,排除安全隐患。在其他语言中实现 contravariance 类比之前的 covariance,把 out 改为 in 即可。如下所示, 以限制 T 只能出现在 public 的方法括号内部(in),内含的全局 T 型变量同样只能为 private,实现只写。

至此,已经把 covariance 和 contravariance 介绍完毕,相信你已经领悟了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值