协变和逆变指的是宽类型和窄类型在某种情况下的替换或交换的特性。

  • 协变就是用一个窄类型替代宽类型
  • 逆变则用宽类型覆盖窄类型。

协变

在Java中协变的例子非常常见,例如,面向对象的多态,以及数组的协变特性,下面看一下协变的例子:

public class Test
{
    public static void main(String[] args)
    {
        Number num1 = new Integer(0);
        Number[] num2 = new Integer[10];
    }
}

而在泛型是不支持协变的,看下面的代码:

public class Test
{
    public static void main(String[] args)
    {
        List<Object> list = new ArrayList<String>();//编译错误
        list = new ArrayList<Object>();
    }
}

虽然泛型不支持协变的,但是可以通过通配符进行模拟:

public class Test
{
    public static void main(String[] args)
    {
        List<? extends Object> list = new ArrayList<String>();
    }
}

注意:? extends Object的含义是:支持Object的子类,也包括Object,作为泛型参数。

逆变

在Java中不允许将父类变量赋值给子类变量。泛型自然也不支持逆变。但是在泛型中可以通过通配符进行模拟,如下例子:

public class Test
{
    public static void main(String[] args)
    {
        List<? super Integer> list = new ArrayList<Number>();
    }
}

注意:? super Integer的含义是:支持Integer的父类,也包括Integer类,作为泛型的参数。

泛型中的 <? extends E><? super E>的含义

  • <? extends E>指泛型参数支持E及E的子类
  • <? super E>指泛型参数支持E及E的父类

代码示例:

有三个类Fruit、Apple和Orange,Fruit是Apple和Orange的父类。

class Fruit{

}

class Apple extends Fruit{

}
class Orange extends Fruit{

}

// list可以包含任何Fruit的子类和Fruit本身
List<? extends Fruit> list = new ArrayList<Orange>();   
// list2可以包含任何Orange的父类及Orange本身
List<? super Orange> list2 = new ArrayList<Fruit>();

本文转载自:Java语言中的协变和逆变


本文转载:CSDN博客