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

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

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

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

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

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

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

我们一般的思维会认为Cage<Anamal> cage = new Cage<Dog>(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 {}

那么 <? extends Anamal> 就表示:

extends

而<? super Anamal>就表示:

super

<? extends T>会导致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,这个标识符不能匹配任何类,所以插入数据的时候不管插入什么对象都会报错,总之就是<? extends T> 下界限制符不允许插入数据。

<? super T> 允许插入数据和获取数据,但是获取的数据是Object类型:

Cage<? extends Anamal> cage = new Cage<Dog>(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)原则: 

第一、 频繁往外读取内容的,适合用<? extends T>;

第二、 经常往里插入的,适合用<? super T>。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值