我正在努力解决 Java 8 通配符泛型问题。
假设有一个泛型类(来自 Core Java 书籍)名为 Pair<T>
class Pair<T> {
private T first;
private T second;
public Pair() {
first = null;
second = null;
}
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; }
}
假设以下类层次结构:
基础员工(层次结构的顶部),然后
Manager 扩展 Employee,然后
主管延伸经理
下面的代码可以工作,但我不明白为什么允许它。
Pair<? super Manager> pm2 =
new Pair<>(
new Employee(1,"Yuri"), // Employee is super of Manager
new Executive()); // Executive is not super of Manager
// why Executive is allowed in above Pair<T> ?
Employee ex1 = (Employee) pm2.getFirst(); // OK
Manager ex2 = (Manager) pm2.getSecond(); // OK
Executive ex3 = (Executive) pm2.getSecond(); // why is allowed?
我不明白为什么 Executive 在上面工作,因为它不是父类(super class)型,而是 Manager 的子类型。
是因为Java 8编译器转换了吗? super 经理到反对,因此任何事情都会被允许?
最佳答案
如您声明:
Pair<? super Manager> pm2 = ...
Pair
接受泛型的方法可以将泛型替换为 Manager
及其子类(在您的情况下为 Executive
)。
因此从逻辑上讲,当您使用泛型调用方法时,您将得到以下结果:
Pair<? super Manager> pm2 = ...;
pm2.setFirst(new Executive()); // compile
pm2.setFirst(new Manager()); // compile
pm2.setFirst(new Employee()); // doesn't compile
最后,就像您没有使用任何通配符一样:
Pair<Manager> pm2 = ...;
pm2.setFirst(new Executive()); // compile
pm2.setFirst(new Manager()); // compile
pm2.setFirst(new Employee()); // doesn't compile
因此,在您的示例中,您使用的下限通配符是无助的。
事实上,这是最糟糕的,因为您使用它来从泛型类型中放入和获取内容,而下限通配符旨在放入内容,而不是从中获取内容。
而您必须执行的强制转换却无法实现通用目的(类型安全):
Employee ex1 = (Employee) pm2.getFirst(); // OK
Manager ex2 = (Manager) pm2.getSecond(); // OK
Executive ex3 = (Executive) pm2.getSecond(); // why is allowed?
那么我们需要如何使用Pair<? super Manager>
?
正如我们想要的通用集合 Pair
可以分配给其他Pair
类型来“放入”东西。
最常见的用例是声明一个接受泛型类型 <? super>
的方法。 .
但在这种情况下,我们希望将未知类型限制为特定类型或父类(super class)型,以防止“放置”可能损害作为参数传递的泛型类型的类型安全性的内容。
例如,假设您需要一个接受 Pair
的方法的Manager
实例并将内容放入 Pair
。
您不希望客户端方法可能传递 Pair<Executive>
否则,如果我们添加Manager
,它可能会破坏通用安全性。因为 Manager
没有必要Executive
实例。这里就是下界通配符的主要作用。
示例代码来说明:
public void putStuff(Pair<? super Manager> managers) {
if (...){
managers.setFirst(new Manager());
}
else if (...){
managers.setFirst(new Executive());
}
}
现在只有 Manager
的类型或父类(super class)型对于Pair
可以传递泛型类型:
putStuff(new Pair<Manager>(...)); // compile
putStuff(new Pair<Employee>(...)); // compile
putStuff(new Pair<Executive>(...)); // doesn't compile
关于Java 通配符有界泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51706027/