我有几个关于Java中通配符的问题:
List<? extends T>
和List<? super T>
之间有什么区别?什么是有界通配符,什么是无界通配符?
我有几个关于Java中通配符的问题:
List<? extends T>
和List<? super T>
之间有什么区别?
什么是有界通配符,什么是无界通配符?
<? extends T>
和<? super T>
是有界通配符的例子。无界通配符看起来像<?>
,基本上表示<? extends Object>
。它松散地表示泛型可以是任何类型。有界通配符(<? extends T>
或<? super T>
)通过指定必须要么扩展特定类型(<? extends T>
称为上限),要么是特定类型的祖先(<? super T>
称为下限)来对类型进行限制。<? super C>
的意思是你的类型被限制为类型层次结构中位于C
上方的某些类型。很抱歉回复晚了,我想两年前我们还没有评论通知功能? - Bill the LizardA
,B
是 A
的子类,而 C
和 D
都是 B
的子类,则如下所示。class A {}
class B extends A {}
class C extends B {}
class D extends B {}
然后
List<? extends A> la;
la = new ArrayList<B>();
la = new ArrayList<C>();
la = new ArrayList<D>();
List<? super B> lb;
lb = new ArrayList<A>(); //fine
lb = new ArrayList<C>(); //will not compile
public void someMethod(List<? extends B> lb) {
B b = lb.get(0); // is fine
lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B
}
public void otherMethod(List<? super B> lb) {
B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A
lb.add(new B()); // is fine, as we know that it will be a super type of A
}
一个有界通配符就像 ? extends B
,其中 B
是某种类型。也就是说,该类型是未知的,但是可以对其进行“限定”。在这种情况下,它被某个类所限定,该类是B的子类。
List<? super B>
的描述是 List 接受的类型是类 B 的父类?这就是为什么 C 和 D 不能编译的原因吗? - knoxgon在这个Google IO 视频演讲中,Josh Bloch 也对何时使用 super
和 extends
作了很好的解释,并提到了“生产者 extends
消费者 super
”这个助记符。
来自演示文稿:
假设您想要向
Stack<E>
添加批量方法
void pushAll(Collection<? extends E> src);
– src 是一个生产 E 的对象
void popAll(Collection<? super E> dst);
– dst 是一个消费 E 的对象
有时候,您可能希望限制可以传递给类型参数的类型。例如,一个操作数字的方法可能只想接受Number或其子类的实例。这就是有界类型参数的作用。
Collection<? extends MyObject>
意味着它可以接受所有与MyObject具有IS-A关系的对象(即任何类型为myObject的子类或者我们可以说是任何MyObject类的对象),或者一个MyObject类的对象。
例如:
class MyObject {}
class YourObject extends MyObject{}
class OurObject extends MyObject{}
Collection<? extends MyObject> myObject;
只接受MyObject或者MyObject的子类(例如OurObject或YourObject或MyObject类型的任何对象,但不包括MyObject的超类的任何对象)。
? extends E
的元素,我们可以从结构中获取元素,但无法将元素放入结构中。List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); // compile-time error
assert ints.toString().equals("[1, 2, 3.14]");
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
通配符用于创建更具可重用性的操作Collection的方法。
例如,如果一个方法有一个参数List<A>
,我们只能给这个方法提供List<A>
。在某些情况下,这种方法的功能是浪费的:
List<A>
中读取对象,则应该允许将List<A-sub>
提供给该方法。(因为A-sub是一个A)List<A>
中插入对象,则应该允许将List<A-super>
提供给该方法。(因为A是一个A-super)通过示例学习:
考虑在Collections
类中使用既有extends
又有super
的sort()
方法:
public static <T extends Comparable<? super T>> void sort(List<T> list){...}
所以
为什么要使用 <T extends Comparable<...>>
: 因为我们需要列表项 (T
) 是 Comparable
接口的子类。
为什么要使用 Comparable<? super T>
: 因为我们允许 Comparable
类型是 T 的任何超类型的 Comparable。
考虑一下
interface Comparable<T>{
public int compareTo(T o);
}
public static <T extends Comparable<? super T>> void sort(List<T> list){...}
public static <T extends Comparable<T>> void sort2(List<T> list){...}
class A implements Comparable<A>{
@Override
public int compareTo(A o) {
...
}
}
class B extends A {
}
List<A> listA = new ArrayList<>();
List<B> listB = new ArrayList<>();
sort(listA); //ok
sort(listB); //ok
sort2(listA); //ok
sort2(listB); //Error