赞
踩
Java泛型中的?指通配符,泛指所有类型。而 extends T>指的是上界通配符,? super T指的是下界通配符。
1 为什么要用通配符和边界?
举个例子,我们假设有一个Cat类表示所有的猫科动物,那么显然加菲猫类Garfield是Cat的一个子类。如果我们有一个猫科动物的笼子List,我们理所当然地认为这个笼子也可以关加菲猫。但是,下面这行代码却在编译期报错了。
List cats = new ArrayList();
所以,我们可以知道,就算容器中存放的对象类型有继承关系,容器间却是没有继承关系的。为了让容器间也存在类似的继承关系,通配符边界就应运而生了。
2 什么是上界?
List extends T>表示这个List对象可以存放T和T的一切子类对象,由此,编译器认为List extends T>是List的父类,所以我们按照如下方式赋值是不会报错的。
List extends Cat> cats = new ArrayList();
然而,使用<?extends Cat>定义的List是不可以再存放任何元素的,因为编译器仅仅知道你集合中对象的类型都是?,具体是啥类型并不知道,所以肯定不能让你乱放元素,万一你放了个Object对象,那集合中的对象类型就乱套了,不再是Cat或Cat的子类。
使用<?extends Cat>定义的List的get()方法正常,因为取出来的元素都可以向上转型成Cat对象。
3 什么是下界?
List super T>表示这个List对象可以存放T和T的一切父类对象。但是,List super Cat>是List的父类,但是却不是List的父类。也就是说,下面这行代码编译期就会报错。
List super Cat> cats = new ArrayList();
但是这样赋值就不会报错:
List super Cat> cats = new ArrayList();
使用 super Cat>定义的List的get()方法会部分失效,因为所有取出来的对象都会转型为Object对象,从而丢失对象原来的信息。set()方法正常。
import java.util.ArrayList;
import java.util.List;
public class AnimalCatGarfield {
public static void main(String[] args) {
List animals = new ArrayList<>();
List cats = new ArrayList<>();
List garfields = new ArrayList<>();
animals.add(new Animal());
cats.add(new Cat());
garfields.add(new Garfield());
// 编译出错,extendsCatFromAnimal只能赋值Cat或Cat子类的集合
List extends Cat> extendsCatFromAnimal = animals;
// 编译成功
List super Cat> superCatFromAnimal = animals;
// 下面两行均编译成功
List extends Cat> extendsCatFromCat = cats;
List super Cat> superCatFromCat = cats;
// 编译成功
List extends Cat> extendsCatFromGarfield = garfields;
// 编译出错,superCatFromGarfield只能赋值Cat或Cat的父类集合
List super Cat> superCatFromGarfield = garfields;
// 测试add方法
// 下面三行均编译失败,除了null以外,任何元素都不能被添加进 extends T>集合内
extendsCatFromCat.add(new Animal());
extendsCatFromCat.add(new Cat());
extendsCatFromCat.add(new Garfield());
// 编译失败,只能添加Cat或Cat子类的集合
superCatFromCat.add(new Animal());
// 下面两行均编译成功
superCatFromCat.add(new Cat());
superCatFromCat.add(new Garfield());
// 测试get方法
// 所有super操作都能够返回元素,但是泛型丢失,只能返回Object对象
// 以下extends操作能够返回元素
Object catExtends2 = extendsCatFromCat.get(0);
Cat catExtends1c = extendsCatFromCat.get(0);
// 编译出错,虽然Cat集合从Garfield赋值而来,但是类型擦除后,是不知道的
Garfield garfield1 = extendsCatFromGarfield.get(0);
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。