Java 泛型通配符上下界理解及应用

一.通配符的应用

实践检验真理,所以在说明通配符上下界的理解的时候,先说明下什么时候使用通配符

关于泛型
类型通配符的作用是为了代替泛型类的类型实参

当我们使用泛型类作为参数时,我们不想固定具体的泛型类型实参,而是想接收任意类型,或者某个类及其子类或超类类型作为类型实参,这个时候就需要使用通配符了,使用泛型类作为类型实参
总结来说通配符解决的问题就是:类B是类A子类,但是泛型类不是泛型类的子类,但是我们又想有这么个类型能同时接收泛型类泛型类类型作为参数的问题

通配符类型

  • 无边界通配符:
    使用无边界通配符可以让泛型接收任意类型的数据

  • 上边界通配符 :<?extends 具体类型 >
    使用固定上边界的通配符的泛型可以接收指定类型及其所有子类类型的数据,这里的指定类型可以是类也可以是接口

  • 下边界通配符 :
    所有固定下边界的通配符的泛型可以接收指定类型及其所有超类类型的数据。

通配符无法同时指定上下边界

举个栗子
我们常用的List就是一个泛型类,以java.lang.Number类及其子类,超类作为类型实参,具体继承关系如下:


看下下面这段代码:

private List data;

    private void test() {
        List numbers = new ArrayList<>();
        List integers = new ArrayList<>();
        //List data = integers; //编译报错
        data = numbers;
        data = integers;
    }

显然虽然IntegerNumber的子类,但是List并不是List的子类,所以List类型的变量不能直接赋值给List的变量。这时候通配符就起到作用了List可以看做是ListList的子类,它可以接收Number类或者其子类型作为类型形参的泛型数据。
所以当我们要在一个方法或者类中接收不固定类型实参的泛型数据,可以考虑使用通配符

二.关于通配符的上下界

1. 无边界 和 上边界通配符

使用无边界和上边界通配符的泛型不能赋值(除了null),可以取值,但是只能去指定的类型及其超类类型(无边界只能取Object类型数据)

(无边界其实上边界就是Object)

List为例:下面这段代码当我们用List或者Listadd数据时发现都会编译报错。
为什么:根据上面应用的结论,ListListList这些类型可以理解为List或者List的子类型。
这时候List或者List add时候不知道到底要往ListListList还是其他Number子类型的Listadd数据的是IntegerLong还是Double类型。这么操作可能会引发类型不一致的问题,这显然和泛型的设计是相悖的。因此Java为了保证类型一致,是不允许这么操作的。但是null是所有引用类型都有元素,所有可以add成功。

List data = new ArrayList<>();
List data = new ArrayList<>();
data.add(new Object()); //编译报错
data.add(10);  //编译报错
data.add(null);

 List numbers = new ArrayList<>();
numbers.add(10); //编译报错
numbers.add(new BigDecimal(20)); //编译报错
numbers.add(null);

在看一下get取值方法:
下面代码可以看出(忽略运行错误啊,只是为了说明泛型编译问题):get方法是可以取到指定类型及其超类型的数据。

List data = new ArrayList<>();
Object object = data.get(0);

List numbers = new ArrayList<>();
Number number = numbers.get(0);
Object number2 = numbers.get(0);
2.下边界通配符

与无边界和上边界通配符相反,下边界通配符只能取Object类型的数据,但可以赋值,只要是指定类型或者其子类型都能成功赋值

还是以List类为例,代码如下,对应到List里面就是add指定类型及其子类型数据时可以正常编译通过,但是get方法不能编译通过
为什么:因为LongBigDecimalFloat都是Numer的子类,根据之前的结论? super Number代表可以接收指定类型及其父类型的数据,所以List可以理解为List或者List的父类型,显然List或者List是可以add Numer的子类型数据的。但是get的时候因为不知道具体是
List还是List或者是之间的什么类型,所以只能get所以类型的父类型Object`类型

List data = new ArrayList<>();
data.add(10);
data.add(new BigDecimal(1000));
data.add(10.07f);
data.add(new Object()) //编译报错

Object object = data.get(0);
Number number = data.get(0); //编译报错

你可能感兴趣的:(Java 泛型通配符上下界理解及应用)