在泛型中,通配符 ? 是比较难理解的一部分,这里,我们介绍下 上界和下界。直接给代码,在代码中看注释比较清晰。
首先我们先准备一些类:
public class Pair<T> {
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
public void setFirst(T newValue) {
first = newValue;
}
public void setSecond(T newValue) {
second = newValue;
}
}
class Employee {
private String name;
private double salary;
public Employee(String n, double s) {
name = n;
salary = s;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
}
class Manager extends Employee {
public Manager(String n, double s) {
super(n, s);
}
}
现在进行测试:注释就是解释。
public class PairTest {
// 这里要先知道,一个已知类型的容器,只能存放同种类型的数据(Object 容器除外)
public static void main(String[] args) {
Manager mgr1 = new Manager("Jack", 10000.99);
Manager mgr2 = new Manager("Tom", 10001.01);
Pair<Manager> managerPair = new Pair<Manager>(mgr1, mgr2);
PairTest.printEmployeeBoddies(managerPair);
// ? extends T 上界通配符 不能往里存,只能往外取
// 用一个<? extends Employee> 接收一个 <Manager> ,因为 manager 是 Employee的子类
Pair<? extends Employee> empPair = managerPair;
// 这里,用 get 方法并没有出错
PairTest.printEmployeeBoddies(empPair);
// 但是用 set 方法就报错
// empPair.setFirst(new Employee("zx",1234.0));
// idea 提示 :
// setFirst(capture<? extends Employee>) in Pair cannot be applied to(Employee)
// 意思就是 ? extends Employee 类型 不能应用于 Employee 类型
// 因为 ? 通配符 表示任意,? extends Employee 表示只要是 Employee 的子类,我都可以在初始化让他自来,
// 并设置一个标识 CAP#1,而不是具体的字类类型,所以在初始化之后,
// 我想给这个对象添加具体类型的子类时,因为子类型与标识 CAP#1 没法匹配,所以就不允许添加
// 但是 我获取的时候,我知道CAP#1肯定是 Employee 本身或子类,所以我可以把一个子类赋值给其父类
// 就是简单的 父类声明子类实例化
/*
empPair.setFirst(new Employee("as",1.2)); // 报错
Pair<? extends Employee> 我们将 T 参数替换后,我们得到如下代码
? extends Employee first 擦拭 类型后 变成了 Employee first
? extends Employee getFirst() // 这里因为标识类型 肯定是 Employee 的子类或本身都可以赋值
void setFirst(? extends Employee newVale) // 这里 因为不能够确定 新值的类型,所以报错。
*/
// ? super T 下界通配符
Pair<? super Manager> pair = new Pair<Employee>(null, null);
minMaxSal(new Manager[] {mgr1, mgr2}, pair);
// Object pairFirst = pair.getFirst();
// Employee employee = (Employee) pairFirst;
// System.out.println(employee.getName());
// Employee employFirst = pair.getFirst(); // 报错
// idea 提示 :
// Incompatible types. Required:Employee. Found: capture<? super Manager>
// 意思是 我们需要返回的是Employee 类型,而捕获到的返回值却是 ? super Manager
// 大家会产生一个问题,我们明明放的就是 Employee 类型,为什么获取出来的数据还得需要我们强转
// 因为 super 只的是父类,只要是Manager 的父类都可以,所以在设置参数的情况下,不报错,因为 Employee 是Manager 的父类
// 但是 我们在获取的情况就不一样的,获取出来时,编译器不知到是哪个父类,所以就统一采取了 Object 超类作为返回值,而在set 时,编译器可以半确定,肯定就是 Manager 本身或其父类并且父类顶端就是 Object, 所以用 set 的时, 只能够将数据保存到 Object 对象上。
/*
Pair<? super Manager> T 参数替换后,得到如下方法
? super Manager getFirst() 我们在获取的时候,不能够确定 ? 代表的是哪个类型 因为标识 CAP#1 不能够确定,但能确定的是 肯定是 Object 是所有类的基类
void setFirst(? super Manager) 这里我们只能确定只要是 Manager 的父类就行。编译器虽然无法确定要set的类型,但可以肯定,
一定是 Manager 的父类,并且是 Object 的子类或者这两者。
所以就把 丢进来的对象赋值到了 Object 上。
*/
}
public static void printEmployeeBoddies(Pair<? extends Employee> pair) {
System.out.println(pair.getFirst().getName() + ":" + pair.getSecond().getName());
}
public static void minMaxSal(Manager[] mgrs, Pair<? super Manager> pair) {
if (mgrs == null || mgrs.length == 0) {
return;
}
pair.setFirst(mgrs[0]);
pair.setSecond(mgrs[0]);
}
}