让我们说我有以下代码:
public class Shelter<A extends Animal, B extends Animal>
{
List<A> topFloor = new Vector<A>();
List<B> bottomFloor = new Vector<B>();
public A getFirstTopFloorAnimal(){return topFloor.get(0);}
public B getFirstBottomFloorAnimal(){return bottomFloor.get(0);}
//These 3 methods compile but when I try to use it, they all only return objects
public List<Animal> getAnimals()
{
List<Animal> a = new Vector<Animal>(topFloor);
a.addAll(bottomFloor);
return a;
}
public List<A> getTopFloor(){return topFloor;}
public List<B> getBottomFloor(){return bottomFloor;}
}
然后我尝试做以下事情:
for(Animal a : shelter.getTopFloor()){
a.growl();
}
但是我编译错误,我得到的错误是A是一个对象,而不是动物。如果我尝试使用其他方法,也会发生同样的情况。任何想法为什么会这样?这与List<String>
是否与Generics教程中的List<Object>
想法有关吗?
谢谢
答案 0 :(得分:4)
泛型只是一个编译时的概念,以提高类型安全性。
您不能使用它们来过滤在运行时添加到集合的值。您必须手动进行过滤(例如,使用instanceOf
)
例如,这可以使用,并允许您添加Date
:
List<String> list = new ArrayList<String>();
((List) list).add(new Date());
因此,在添加元素时,您(我们尚未看到的)问题的解决方案是不使用原始类型。
答案 1 :(得分:2)
我最好的猜测是你已声明shelter
使用原始类型,如下所示:
Shelter shelter = new Shelter();
你真的应该做到以下几点:
Shelter<Cat,Dog> shelter = new Shelter<Cat,Dog>();
然后你实际上使用了泛型功能。
Effective Java 2nd Edition :第23项:不要在新代码中使用原始类型。
如果使用原始类型,则会失去仿制药的所有安全性和表现力。
原始类型的使用仅允许作为遗留代码兼容性的让步。强烈建议不要在将通用性引入Java编程语言之后编写的代码中使用原始类型。 未来版本的Java编程语言可能会禁止使用原始类型。
List<String>
不是List<Object>
是的,Java泛型既不是covariant nor contravariant。如果你试图将一个泛型类型转换为另一个类型,这只是一个问题,这似乎不是你想要做的。
此外,与主题标题所说的不同,我认为这与extends
无关,无法在泛型中绑定类型参数。
答案 2 :(得分:1)
我认为问题的核心在于:
for(Animal a : shelter.getTopFloor()){
a.growl();
}
如何定义shelter
?
答案 3 :(得分:0)
这是因为当您将项目放在Vector
中时,它们会作为对象进入,而不是Animal
的实例。
public List<Animal> getAnimals()
{
Vector a = new Vector(topFloor); // <-- Not generic!
a.addAll(bottomFloor);
return a; // <-- Returning non-generic Vector.
}
请改为尝试:
Vector<Animal> a = ...