在OO中,协变是指按照继承链正向改变把子类当做父类用,逆变是指逆向改变.把父类当做子类用
所谓协变也就是满足里氏替换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象。
协变的例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
泛型是不支持协变的,看下面的代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
虽然泛型不支持协变的,但是可以通过通配符进行模拟:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
注意:? extends Object的含义是:支持Object的子类,也包括Object,作为泛型参数。
在Java中不允许将父类变量赋值给子类变量。泛型自然也不支持逆变。但是在泛型中可以通过通配符进行模拟,如下例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
注意:? super Integer的含义是:支持Integer的父类,也包括Integer类,作为泛型的参数。
List<? extend Fruit> list=new ArrayList<>(); 解释为:集合中元素是继承自Fruit,究竟是何种类型,编译器也无法判定。
如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)
List<? super Apple> list=new ArrayList<>();解释为:集合中的元素是Apple的父类,无法判定具体类型。
如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)
如果既要存又要取,那么就不要使用任何通配符。
协变重载
class Grain
{
public String toString()
{
return "Grain";
}
}
class Wheat extends Grain
{
public String toString()
{
return "Wheat";
}
}
class Mill
{
Grain process(){
return new Grain();
}
}
//协变
class WheatMill extends Mill{
Wheat process(){
return new Wheat();
}
}
//逆变
class KangBian extends WheatMill
{
Grain process() //父类WheatMill中返回的是Wheat,这里返回的是其父类,逆变不支持,会出现编译错误
{
return new Grain();
}
}
public class NewTest{
public static void main(String[] args)
{
Mill m = new Mill();
Grain g = m.process();
System.out.println(g);
m = new WheatMill();
g = m.process();
System.out.println(g);
KangBian k = new KangBian();
g = k.process();
System.out.println(g);
}
}
<完>