【发布时间】:2013-03-04 11:57:30
【问题描述】:
为什么以下不起作用?
Vector<? extends SomeClass> v = new Vector<SomeClass>();
SomeClass e = new SomeClass();
v.add(e);
我得到一个编译错误:
类型中的方法add(capture#1-of ? extends SomeClass) 向量不适用于 参数(SomeClass)
【问题讨论】:
为什么以下不起作用?
Vector<? extends SomeClass> v = new Vector<SomeClass>();
SomeClass e = new SomeClass();
v.add(e);
我得到一个编译错误:
类型中的方法add(capture#1-of ? extends SomeClass) 向量不适用于 参数(SomeClass)
【问题讨论】:
从一个类型扩展的带有generic wildcards 的集合不允许您添加到该Collection。
由于编译器不知道您尝试添加的SomeClass 的确切类型,因此它不允许添加。一个例外是null 对象,它可以表示任何类型的Object。
回答您的评论:虽然您不能添加到Collection,但它不能被描述为只读,因为它仍然可以删除 Objects.
要允许添加Objects,您需要使用已知类型:
Vector<SomeClass> v = new Vector<SomeClass>();
【讨论】:
Vector<? super SomeClass> 确实允许您添加到集合中。
问题基本上是通过将v 声明为Vector<? extends SomeClass> 你说它是SomeClass 的集合或它的一个子类。即使对new Vector<SomeClass>() 的赋值是在同一行完成的,编译器也无法对容器实际保存的特定类型做出任何假设。据编译器所知,v 可能已创建为new Vector<SubClassOfSomeClass>()。这就是为什么它拒绝将SomeClass 实例(或其他任何东西)放入 到集合中。但是,您可以从中获取 SomeClass 元素。
如果您希望能够放入元素到集合中,则将v 声明为Vector<? super SomeClass>,这样您就可以说它是SomeClass 的容器或 它的超类之一。然后编译器知道SomeClass 实例肯定适合这样的集合。
但是,您不能从该集合中获取 SomeClass 元素,因为编译器对其中的元素类型一无所知(除了它是SomeClass 的某个超类)。根据v 的定义,它也可能只是Objects 的集合。
这被简称为put/get 原则,在this等其他帖子中也有详细讨论。
【讨论】:
这已解释here。这样声明的列表实际上是一个只读列表,但它比普通的List<AbstractClass> 列表更灵活。
如果您想使用抽象类作为模板,只需像这样直接使用它:List<SomeClass> list。
考虑阅读Java language specification,有很多关于泛型逻辑的信息。
【讨论】:
你的问题解释应该没有问题。我在以下代码中理解了您的问题。
import java.util.*;
class Test
{
int x;
}
public class Demo
{
public static void main(String args[])
{
Vector<Test> vect = new Vector<Test>();
Test t1 = new Test();
Test t2 = new Test();
t1.x = 10;
t2.x = 20;
vect.add(t1);
vect.add(t2);
for(Test t : vect)
{
System.out.println(t.x);
}
}
}
我在Vector Play With看到了这种噱头。
【讨论】: