泛型通配符1

73 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第40天,点击查看活动详情

我们在定义泛型类,泛型方法,泛型接口的时候经常会碰见很多不同的通配符,比如 T,E,K,V,? 等等,下面来详细讲一下这些通配符。

常用的通配符

本质上都是通配符没啥区别,只不过是编码时的一种约定俗成的东西(可以说提高了代码可读性)。比如上述代码中的 T ,我们可以换成 A-Z 之间的任何一个大小写字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替 T ,在可读性上可能会弱一些。通常情况下,T,E,K,V,? 是这样约定的:

  • ? 表示不确定的 java 类型
  • T (Type) 表示具体的一个java类型
  • K V (Key Value) 分别代表java键值中的Key Value
  • E (element) 代表Element

比较难的就是通配符,下面就着重讲一下

‘ ? ‘无界通配符

基本用法

List<Animal> listAnimals

但是如果用通配符的话:

List<? extends Animal> listAnimals

为什么要使用通配符而不是简单的泛型呢?通配符其实在声明局部变量时是没有什么意义的,但是当你为一个方法声明一个参数时,它是非常重要的。

package keyAndDifficultPoints.Generic;

import java.util.ArrayList;
import java.util.List;

/**
 * 功能描述: 泛型通配符测试
 */
public class Test_Wildcard_Character {

    public static void main(String[] args) {
        List<Dog> dogList = new ArrayList<>();
        test(dogList);
        test1(dogList);
    }

    static void test(List<? extends Animal> animals) {
        System.out.println("test输出:");
        for (Animal animal : animals) {
            System.out.print(animal.toString() + "-");
        }
    }

    static void test1(List<Animal> animals) {
        System.out.println("test1输出:");
        for (Animal animal : animals) {
            System.out.print(animal.toString() + "-");
        }
    }


}

class Animal {
    @Override
    public String toString() {
        return "Animal";
    }
}

class Dog extends Animal {
    @Override
    public String toString() {
        return "Dog";
    }
}

方法test1()在编译时就会飘红,如下图:

image.png

所以,对于不确定或者不关心实际要操作的类型,可以使用无限制通配符(尖括号里一个问号,即 <?> ),表示可以持有任何类型。像 test()方法中,限定了上界,但是不关心具体类型是什么,所以对于传入的 Animal 的所有子类都可以支持,并且不会报错,而test1()就不行。

‘ ? ‘通配符的继承

    /*
    2. 通配符的使用
       通配符:?

       类A是类B的父类,G<A>和G<B>是没有关系的,二者共同的父类是:G<?>
     */

    @Test
    public void test3() {
        List<Object> list1 = null;
        List<String> list2 = null;

        List<?> list = null;

        list = list1;
        list = list2;
        //编译通过
//        print(list1);
//        print(list2);


        //
        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");
        list = list3;
        //添加(写入):对于List<?>就不能向其内部添加数据。
        //除了添加null之外。
//        list.add("DD");
//        list.add('?');

        list.add(null);

        //获取(读取):允许读取数据,读取的数据类型为Object。
        Object o = list.get(0);
        System.out.println(o);


    }