Java 泛型 ? super T 中 super 怎么 理解与 ? extends T 有何不同?

首先说一下java泛型吧,泛型是Java SE 1.5的新特性,用来在编译时做类型检查的,并且会根据泛型类型自动进行类型转换,也就是说,泛型只在编译期起作用,主要是用来保证类型安全的,编译后的class文件中是不会包含泛型的,这个大家可以将class文件反编译过来看看。

表示java泛型中的上界和下界的概念,就是说限定的是容器中所能接收的最顶层的父类,也就是T和T的子类; 限定的是容器中所能接收的最底层的子类,也就是T和T的父类。

举个例子:我们有一个动物类Animal,分别有两个子类Dog和Cat:

Class Animal {}
Class Dog extends Animal {}
Class Cat extends Animal {}

同时我们还有一个笼子类,里面包含了放入和取出的方法,因为笼子不仅仅可以放动物,也可以放其他的东西,所以我们定义成泛型T:

Class Cage {
    private T t;
    public Cage (T t) {
        this.t = t;
    }
    public T get() {
        return t;
    }
    public void set(T t) {
        this.t = t;
    }
}

我们一般的思维会认为Cage cage = new Cage(new Dog),放动物的笼子肯定可以放狗吧,然而并不是,这行代码会编译报错,因为在虚拟机看来,虽然狗是一个动物,但是装动物的笼子并不一定是装狗的笼子。简而言之就是说这种写法左边的泛型是什么,右边的泛型就必须定义成什么。

接下来我们在丰富一下我们的类对象,假设所有的动物都继承自生物,生物类有动物和植物两个子类,狗又包含大狗和小狗,猫又包含黑猫和白猫:

Class Biology {}

Class Anamal extends Biology{}
Class Dog extends Anamal {}
Class BigDog extends Dog {}
Class SmallDog extends Dog {}
Class Cat extends Anamal {}
Class BlackCat extends Cat {}
Class whiteCat extends Cat {}

Class Plant extends Biology{}
Class Flower extends Plant {}
Class Tree extends Plant {}

那么 就表示:

Java 泛型 ? super T 中 super 怎么 理解与 ? extends T 有何不同?_第1张图片

就表示:

Java 泛型 ? super T 中 super 怎么 理解与 ? extends T 有何不同?_第2张图片

会导致set方法编译报错:

//不能调用set方法
cage.set(new Dog());    //编译错误
cage.set(new Cat());    //编译错误

//调用get方法获取到的是一个Anamal类型的对象,需要自己强转
Anamal anamal = cage.get();
Dog dog = (Dog) cage.get();
Dog dog2 = cage.get();    //编译错误

原因是因为? extends Anamal只知道放进去的是一个Anamal或Anamal的子类,在看到后面用Cage赋值之后,会用一个占位符:CAP#1,这个标识符不能匹配任何类,所以插入数据的时候不管插入什么对象都会报错,总之就是 下界限制符不允许插入数据。

允许插入数据和获取数据,但是获取的数据是Object类型:

Cage cage = new Cage(new Dog());
   
//不能调用set方法
cage.set(new Dog());    //编译通过
cage.set(new Cat());    //编译通过

//调用get方法获取到的是一个Object类型的对象
Anamal anamal = cage.get(); //编译错误
Dog dog2 = cage.get();    //编译错误
Object o = cage.get();    //编译通过

因为? super T是限定了下界,只要是T的父类都可以放,这样一来往外取数据就只能是Object类型的了,因为Object是所有类的父类。

另外扩展说一下 PECS(Producer Extends Consumer Super)原则: 

第一、 频繁往外读取内容的,适合用

第二、 经常往里插入的,适合用

你可能感兴趣的:(java基础)