具有多个边界的Java列表泛型
我很难理解为什么以下代码不起作用:具有多个边界的Java列表泛型,java,list,generics,collections,bounds,Java,List,Generics,Collections,Bounds,我很难理解为什么以下代码不起作用: public <E extends Animal & IQuadruped> void testFunction() { List<E> list = new ArrayList<E>(); Dog var = new Dog(); list.add(var); } 我在add上得到一个编译错误: The method add(E) in the type List<E> is
public <E extends Animal & IQuadruped> void testFunction()
{
List<E> list = new ArrayList<E>();
Dog var = new Dog();
list.add(var);
}
我在add上得到一个编译错误:
The method add(E) in the type List<E> is not applicable for the arguments (Dog)
类型列表中的add(E)方法不适用于参数(Dog)
我只想确保我的列表元素扩展/实现了这两个类,并且满足了这些条件,为什么它不工作
谢谢你这就是你得到的。当JVM执行要添加到列表中的行时,泛型已经丢失。要使其正常工作,您必须执行以下操作:
public <E extends Animal & IQuadruped> void testFunction(E param) {
List<E> list = new ArrayList<E>();
list.add(param);
}
public void addDog() {
testFunction(new Dog())
}
public void测试函数(E参数){
列表=新的ArrayList();
列表。添加(参数);
}
公共无效addDog(){
testFunction(新的Dog())
}
什么是
意思是“既是动物
又是IQuadruped
”的子类型的特定类型,而不是“既是动物
又是IQuadruped
的子类型的任何类型”
很难理解这种区别的原因是,在日常思维中,我们并没有明确区分。例如,如果你同意与某人在餐厅共进午餐,而他们说“下周的任何一天对我都有好处”,你就会自然而然地知道这意味着你需要在同一天出现。并不是说你可以随时去,他们会在那里
在这种情况下,无法保证调用者选择的E
肯定是狗
,因此您的代码无法工作
显然错误的解决方案是指定
,因为这将保证E
是狗的子类型。然而,由于完全相同的原因,这是错误的,E
可以是Dog
的任何子类型,比如说E
是一只Poodle
,所以当你创建列表时,你将无法将你的新狗()
放在那里,因为它不是Poodle
正确的界限是
,因为这意味着E
肯定是一种类型,您可以将Dog
实例强制转换为该类型。它可以是狗
本身,也可以是动物
或被驯服的
甚至对象
。但它保证您可以将狗
放入列表中
这个原则的名称是PECS:producer extends,consumer super,您可以阅读它。我可以调用YourClass.testFunction()
,然后您的函数将创建一个ArrayList
,并向其中添加一个Dog。哈,我现在看到了逻辑中的缺陷,我对它进行了如下修改:code
public void testFunction(E var){List List List=new ArrayList();List.add(var);}code
并将其命名为:code
Dog var=new Dog();testFunction(var);code
有效且更有意义,谢谢:)如果另一方面您将元素作为参数,像这样:public void testFunction(E var)
,它可以工作。即使没有类型擦除,这也是无效的。这个问题是关于协方差和逆变换的。我对此投了反对票,因为这个问题与类型擦除无关。(不过,如果他尝试使用newe()
public <E extends Animal & IQuadruped> void testFunction(E param) {
List<E> list = new ArrayList<E>();
list.add(param);
}
public void addDog() {
testFunction(new Dog())
}