class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class A<T> {
T t;
public void setT(T t) {
this.t = t;
}
T getT() {
return t;
}
}
public static void print1(A<? extends Animal> obj){
//obj.setT(new Cat()); //Line 1
System.out.println(obj.getT().getClass());
}
public static void print2(A<? super Animal> obj){
obj.setT(new Dog()); //Line 2
System.out.println(obj.getT().getClass());
}
我理解为什么第1行不能编译,但完全不理解为什么第2行可以编译。
我正在尝试理解Java中的下限和上限通配符
1条答案
按热度按时间5jdjgkvh1#
在Java泛型中,A<?extends Animal>是一个带有上限的通配符类型声明。这意味着类型参数T可以是Animal的任何子类型(包括Animal本身)。当你有一个带上限的通配符时,它可以确保类型是“只读”的,也就是说你只能检索T类型的值,但不能修改内容。
在print 1方法中,obj用上界通配符A<?扩展Animal>。这意味着您可以调用getT()方法,该方法返回T类型的值(这是Animal的某个子类型),但您不能调用setT()方法,因为T的确切类型未知。编译器无法保证将Cat赋值给T的安全性,因为T可能是Animal的更具体的子类型,例如Dog。
另一方面,A<?super Animal>是一个带有下限的通配符类型的声明。这意味着类型参数T可以是Animal的任何超类型(包括Animal本身)。当您有一个带下限的通配符时,它允许您检索和修改对象的内容。
在print 2方法中,obj是用一个下界通配符A<?super Animal>.这意味着您可以同时调用getT()和setT()方法。setT()方法接受Animal的任何子类型(包括Animal本身),因为任何这样的子类型都是对T的有效赋值(可以是Animal的超类型)。在这种情况下,您可以将Dog分配给T,因为T可以是Dog的超类型(例如,Animal)。