Contents
  1. 1. 介绍
    1. 1.1. 返回值协变
    2. 1.2. 参数的逆变
    3. 1.3. 类型转换
    4. 1.4. 数组支持协变,不支持逆变
    5. 1.5. 泛型不支持协变与逆变,但可以模拟协变与逆变

介绍

  • 简单的说,协变是用一个窄类型替换宽类型,而逆变则是用宽类型覆盖窄类型

返回值协变

1
2
3
4
5
6
7
8
9
10
11
12
class Base{
public Number doSomething(){
return 0;
}
}

class Sub extends Base{
@Override
public Integer doSomething(){
return 0;
}
}

子类的doSomething方法返回值的类型比父类方法更窄,此时doSomething方法就是一个协变方法,同时根据java的覆写定义来看,这又属于覆写。

参数的逆变

1
2
3
4
5
6
7
8
9
class Base{
public void doSomething(Integer i){
}
}

class Sub extends Base{
public void doSomething(Number i){
}
}

子类的doSomething方法的参数类型比父类要宽,此时是一个逆变方法,子类扩大了父类的方法输入参数,同时根据java重载的定义,这又属于重载。

类型转换

1
2
3
public static void main(String[] args){
Base base = new Sub();
}

base变量发生了协变,base变量是Base类型,他是父类,而其赋值却是子类实例,也就是用窄类型覆盖了宽类型。 同时根据多态的定义,这又属于多态。

数组支持协变,不支持逆变


Number[]类型可以成功转换为Integer[]类型
表面类型为Number[],实际类型为Integer[],用窄类型(Integer[])替换了宽类型(Number[]),属于协变

泛型不支持协变与逆变,但可以模拟协变与逆变

例如:

1
2
3
4
5
6
7
8
9
10
List<Number> list = new ArrayList<Integer>();
//Type mismatch: cannot convert from ArrayList<Integer> to List<Number>
泛型结构通过使用通配符模拟协变与逆变:
List<? extends Number> list =new ArrayList<Integer>();
List<? super Integer> list = new ArrayList<Number>();

补:
List<Integer> 不是List<Number>的子类型
List<Integer> 不是 List<? extends Integer>的子类型
List<Integer> 不是 List<? super Integer> 的子类型
Contents
  1. 1. 介绍
    1. 1.1. 返回值协变
    2. 1.2. 参数的逆变
    3. 1.3. 类型转换
    4. 1.4. 数组支持协变,不支持逆变
    5. 1.5. 泛型不支持协变与逆变,但可以模拟协变与逆变