朱红振以Java为例理解协变性-程序设计及计算机基础学习空间

以Java为例理解协变性-程序设计及计算机基础学习空间萌购网

===Tips:点击上方蓝字查看历史消息===

这篇文章以Java为例雨的随想 ,解释下语言的类型系统中的几个重要概念,协变性(covariance)、逆变性(contravariance)和无关性(invariant)。
在面向对象语言中由于继承的存在幻世道 ,安全的类型转换对于书写正确的代码至关重要篡明 。而上面几个概念就是用来描述这种类型转换的性质的。首先看下这几个概念的定义:
如果M和N是类型,f()表示类型转换,≤表示子类型关系,例如M≤N,表示M是N的子类渡狸卍里,那么:
如果M≤N则f(M) ≤f(N),那么f()是协变的;
如果M≤N则f(N) ≤f(M)揸紧中指 ,那么f()是逆变的;
如果上面两种都不成立,那么f()是无关的朱红振。
举个例子古剑奇侠 ,首先规定如下继承规则,后面例子中不另行说明都默认有这个定义C≤B≤A:
classA{ }
classBextendsA{}
classCextendsB{}
然后,规定f(x)=x[ ]无尽破碎。
B[ ]w2=null;
A[ ]q1=w2;
B[ ]q2=w2;
C[ ]q3=w2; //ERROR:编译错误Typemismatch
由上可得,B[]为A[]的子类蔡小虎,这样就证明数组变换具有协变性。这说明在Java中,数组具有协变性,再看个例子:
classAnimal{
publicBdeal(){
returnnull;
}
}
classCatextendsAnimal{
@Override
publicBdeal(){
returnnull;
}
}
Cat继承了deal()方法,deal()的返回值为A则会发生编译错误,返回为B和C则正确。这说明继承覆盖方法返回值具有协变性。那对于继承覆盖方法的参数呢?
classAnimal{
voiddeal(Bt){}
}
classCatextendsAnimal{
@Override
voiddeal(Bt){}
}
Cat的deal方法的参数为A或者C都会报错,这说明继承覆盖方法的参数具有不变性。当然强子哥哥,去掉Override标志后,方法重载deal方法乡村艳医,参数写什么都无所谓,但是那样连类型转换都没有发生高门嫡女,就没有讨论的价值了。塔琳托娅
几个基本的情况都清楚了,下面看下Java的泛型List<?>
List<B>t1=null;
List<B>t2=null;
t1=t2;
很明显,t2的类型为List<A>和List<C>都会报编译错误,这说明List<>和数组不同,具有不变性周镇松!所幸,对于这种尴尬的情况oj梅奥,Java提供了通配符这一功能来解决这一问题,extends和super,前一个代表了协变性,后一个代表逆变性吴琼老公。
List<A>t1=null;
List<B>t2=null;
List<C>t3=null;
List<? extendsB>t=null;
t=t1; //ERROR
t=t2;
t=t3;
List<A>t1=null;
List<B>t2=null;
List<C>t3=null;
List<? superB>t=null;
t=t1;
t=t2;
t=t3; //ERROR
资料引用:http://blog.csdn.net/srzyhead/article/details/10204085