我正在Core Java volume-1 by Horstmann, Cay.S
上阅读generics
。我无法理解教科书的一些解释。我给出了作者所指的示例代码。然后是书中的文字和我的问题。
class Employees{ }
class Manager extends Employees { }
class Pair<T>{
private T first;
private T second;
Pair(T first, T second){
this.first=first;
this.second=second;
}
void setFirst(T value){
first=value;
}
T getFirst(){
return first;
}
}
public class WildCardGenerics {
public static void main(String[] args){
Manager ceo = new Manager();
Manager cfo=new Manager();
Employees clerk = new Employees();
Pair<Manager> managers= new Pair<>(ceo,cfo);
Pair<? extends Employees> employees=managers;
employees.setFirst(clerk);
}
}
从书中可以看出:
“”“不存在腐败。对setFirst
的致电是type error
。为了了解原因,让我们更接近
查看类型Pair<? extends Employee>
。它的方法如下:
? extends Employee getFirst()
void setFirst(? extends Employee)
这使得无法调用setFirst
方法。 compiler
只知道它需要一些subtype
Employees
,但它不知道哪种类型。毕竟,它拒绝pass any specific type
?
可能与之不符。“”“
问题:
我不明白为什么它拒绝传递任何特定类型。那么这种方法接受了什么?
? extends Employee
- 表示包括Employee和Employee的任何子类型。通过员工应该是合法的吗?
从书中可以看出:
pair<? super Manager> has methods:
void setFirst(? super Manager)
? super Manager getFirst()
编译器不知道setFirst
方法的确切类型,因此无法调用它
使用Employee or Object
类型的对象,但只能使用Manager
或subtype
,例如executive
。
问题: 所以在这里我说该方法可以接受任何Manager对象或扩展Manager对象(类似于上面的subytpe)。我不清楚为什么?
从书中可以看出:
Intuitively speaking, wildcards with supertype bounds let you write to a generic object, while
wildcards with subtype bounds let you read from a generic object.
问题: 我根本无法遵循它。这听起来很简单,但并不遵循逻辑意义。
答案 0 :(得分:1)
以下分配是合法的,前提是Clerk
是Employees
[sic]。
Pair<? extends Employees> employees = new Pair<Clerk>(clerk1, clerk2);
您应该无法致电setFirst
并传递Manager
,因为在这里,它确实是Pair<Clerk>
。
这说明了如果存在T
通配符,Java不允许调用其中包含泛型类型参数的方法(? extends
)。编译器不知道它到底是哪个类 - Employee
?一个子类?哪个子类?由于类型擦除,JVM无法检查类型安全性,因此编译器必须禁止除null
之外的所有此类调用,这些调用可以转换为任何引用类型并且始终允许。
使用? super Employee
时,下限为Employee
。它可能是Pair<Object>
。但是,传递Employee
或其子类之一是安全的,因为它们是? super Employee
允许的任何子类。
答案 1 :(得分:1)
始终将? extends T
视为“某些CAP#1
延长T
”,将? super T
视为“CAP#2
延伸的T
。” / p>
现在你的例子更具可读性:
“没有腐败是可能的。对setFirst的调用是一个类型错误。要了解原因,让我们仔细看看类型Pair< some CAP#1 extending Employee >
。它的方法如下:
CAP#1 getFirst()
void setFirst( CAP#1 value )
由于CAP#1
是一种虚构类型,因此您无法使用setFirst()
来呼叫Employee
,因为您无法知道CAP#1
是否为{{1}或者它的一些随机子类型。 Employee
是逆变方法;它使用泛型类型的实例。
但是,无论setFirst()
是什么,它都会延伸CAP#1
,因此您可以致电Employee
并将结果分配给getFirst()
- 变量。 Employee
是协变;它生成泛型类型的实例。
所以你问,如果你不能在这样的变量上使用一半的方法,为什么你会想要一个getFirst()
类型的变量呢?
因为你可以使用通配符类型做的一件事是解决Java中的一些方差问题。无论我有Pair< ? extends Employee >
还是Pair< Employee >
还是Pair< Manager >
,我都可以将该内容分配给Pair< SomeClassExtendingManager >
类型的变量。我无法将Pair< ? extends Employee >
分配给Pair< Manager >
类型的变量,即使Pair< Employee >
中没有逆变方法,因为类型系统无法解决这个问题。