具有多个边界的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())
}