我很难理解为什么以下代码不起作用:
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满足这些条件,为什么它不起作用?
谢谢
答案 0 :(得分:1)
<E extends Animal & IQuadruped>
的含义是&#34;特定类型,它是Animal
和IQuadruped
&#34;的子类型,而不是&#34;任何类型Animal
和IQuadruped
&#34;
难以理解差异的原因在于,在日常思维中,我们并没有明确区分这种区别。例如,如果你同意和餐馆里的某个人一起出去吃午饭,他们说&#34;下周的任何一天对我都有好处,你自动知道这意味着你需要在同一天出现。并不是说你可以随时去,而且他们会在那里。
在这种情况下,无法保证调用者选择的E
肯定会Dog
,因此您的代码无法正常工作。
显而易见的错误解决方案是指定<E extends Dog>
,因为它可以保证E
是Dog
的子类型。但是出于同样的原因这是错误的,E
可以是Dog
的任何子类型,让我们说E
是Poodle
,所以当你创建一个List<Poodle>
时new Dog()
,您无法将Poodle
放在那里,因为它不是<E super Dog>
。
正确的绑定是E
,因为这意味着Dog
绝对是一种可以将Dog
实例强制转换为的类型。它可以是Animal
本身,可以是IQuadruped
或Object
,甚至是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())
}