五、泛型参数的界限(通配符)
20220328 补充:Java中<? extends T>和<? super T>的理解# - chenxibobo - 博客园 (cnblogs.com)
不能往里存,只能往外取
泛型类或者接口中,拥有“不确定的”类型. 但是,我们也可以限定其为“某一部分类型”, 即为某个类的子类。
定义方式: <T extends BoundingType> , T 和 BoundingType 既可以是类,也可以是接口。
那么SimpleClass <BoudingType> 就是 SimpleClass <T> 的父类呢? 其中SimpleClass 是表示一个自定义的类名,通过一个小程序来看看:
public class GenericeTest03 {
public static void main (String[] args) {
Information <Integer> age1 = new Information <Integer> (10);
Information <Number> age2;
age2 = age1; // (1)
}
}
class Information<T> {
private T data;
public Information() {
}
public Information(T data) {
this.data = data;
}
public T getData(){
return data;
}
public void setData(T data) {
this.data = data;
}
}
编译出错:
Exception in thread "main" java.lang.Error: Unresolved compilation problem: Type mismatch: cannot convert from Information<Integer> to Information<Number> at GenericeTest03.main(GenericeTest03.java:8)
由此可以看出, 虽然 Number 类 是Integer类的父类, 但是 Information <Number> 却不是 Information <Integer> 的父类.
实际上 Information <Integer extends Number>, 即可以限定泛型的类型是在某些范围内的, 以确保类型安全.
那有没有存在同时是 Information<Number> 和Information<Integer>的父类,使得程序更加通用? 那就是使用类型通配符 <?>
public class GenericeTest03 {
public static void main (String[] args) {
Information <Integer> age1 = new Information <Integer> (10);
Information <Number> age2 = new Information <Number> (11); // new
//age2 = age1; // (1)
Information <? extends Number> age3; // (2)
age3 = age1; // (3)
System.out.println("age3.getData() = " + age3.getData());
age3 = age2; // (4)
System.out.println("age3.getData() = " + age3.getData());
}
}
class Information<T> {
private T data;
public Information() {
}
public Information(T data) {
this.data = data;
}
public T getData(){
return data;
}
public void setData(T data) {
this.data = data;
}
}
运行结果:
parent.getData() = 10
parent.getData() = 11
(3) 处定义了age3, 使用了类型通配符 < ? extends Number>, 因此,其把 age1 和age2的值赋给它.
即可得出结论: <? extends Number> 是 <Integer> 和 <Number> 的父类.
其中 <? extends Number> 这种称为类型通配符上限,相应的 <? super Number> 称为类型通配符下限。
此外,另个一例子可以更好地理解泛型通配符, 参考: http://www.linuxidc.com/Linux/2013-10/90928.htm
类图很简单, 直接上代码
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void eat() {
System.out.println(getName() + " can eat.");
}
}
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void fly() {
System.out.println(getName() + " can fly.");
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
public void jump() {
System.out.println(getName() + " can jump.");
}
}
public class Magpie extends Bird {
public Magpie(String name) {
super(name);
}
public void sing() {
System.out.println(getName() + " can not only eat, but sing");
}
}
import java.util.List;
public class AnimalTrainer {
/*
public void act (List<Animal> list) {
for (Animal animal : list) {
animal.eat();
}
}*/
public void act (List<? extends Animal> list) { // 具体类型由调用时确定 // public <T extends Animal> act (List <T> list)
for (Animal t: list) {
t.eat();
}
}
}
import java.util.ArrayList;
import java.util.List;
public class TestAnimal {
public static void main (String[] args) {
AnimalTrainer animalTrainer = new AnimalTrainer();
List<Animal> animalList = new ArrayList<>();
animalList.add(new Cat("cat1"));
animalList.add(new Bird("bird1"));
animalTrainer.act(animalList);
List<Bird> birdList = new ArrayList<>();
birdList.add(new Bird("bird2"));
birdList.add(new Bird("bird3"));
animalTrainer.act(birdList);
List<Cat> catList = new ArrayList<>();
catList.add(new Cat("cat2"));
catList.add(new Cat("cat3"));
animalTrainer.act(catList);
}
}
重要的是AnimalTrainer的 act()方法中,定义的泛型参数列表, 能接收来自catList / birdList 的类型。 如果是 void act (List <Animal> list) , 则如果往其加入cat , 则会报错.