具有多个边界的Java列表泛型

时间:2015-07-10 14:41:34

标签: 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);
}

与Dog如下:

public class Dog extends Animal implements IQuadruped
{

}

我在add上遇到编译错误:

The method add(E) in the type List<E> is not applicable for the arguments (Dog)

我只想确保我的列表元素扩展/实现这两个类,并且Dog满足这些条件,为什么它不起作用?

谢谢

2 个答案:

答案 0 :(得分:1)

<E extends Animal & IQuadruped>的含义是&#34;特定类型,它是AnimalIQuadruped&#34;的子类型,而不是&#34;任何类型AnimalIQuadruped&#34;

的子类型

难以理解差异的原因在于,在日常思维中,我们并没有明确区分这种区别。例如,如果你同意和餐馆里的某个人一起出去吃午饭,他们说&#34;下周的任何一天对我都有好处,你自动知道这意味着你需要在同一天出现。并不是说你可以随时去,而且他们会在那里。

在这种情况下,无法保证调用者选择的E肯定会Dog,因此您的代码无法正常工作。

显而易见的错误解决方案是指定<E extends Dog>,因为它可以保证EDog的子类型。但是出于同样的原因这是错误的,E可以是Dog的任何子类型,让我们说EPoodle,所以当你创建一个List<Poodle>new Dog(),您无法将Poodle放在那里,因为它不是<E super Dog>

正确的绑定是E,因为这意味着Dog绝对是一种可以将Dog实例强制转换为的类型。它可以是Animal本身,可以是IQuadrupedObject,甚至是Dog。但它保证您可以在列表中放置if($data && is_array($data->getRows())){ foreach ($data->getRows() as $key => $row) { $analytics['pageviews'] += $row[1]; $analytics['uniquePageviews'] += $row[2]; } }

这个原则的名称是PECS:生产者扩展,消费者超级,你可以阅读它constant cache

答案 1 :(得分:0)

Generics type erasure就是你得到的。当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())
}