简体   繁体   English

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

[英]Java list generics with multiple bounds

I'm struggling to understand why the following code doesn't work : 我正在努力理解以下代码为何不起作用:

public <E extends Animal & IQuadruped> void testFunction()
{
    List<E> list = new ArrayList<E>();
    Dog var = new Dog();
    list.add(var);
}

with Dog being the following : 其中Dog为以下内容:

public class Dog extends Animal implements IQuadruped
{

}

And I get a compile error on the add : 我在添加时遇到编译错误:

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

I just want to make sure my list elements extend/implement both classes, and Dog fullfil those conditions, why is it not working ? 我只想确保列表元素可以扩展/实现两个类,而Dog可以满足这些条件,为什么它不起作用?

Thank you 谢谢

What <E extends Animal & IQuadruped> means is "a particular type that is a subtype of both Animal and IQuadruped ", and not "any type that is a subtype of both Animal and IQuadruped " <E extends Animal & IQuadruped>意思是“既是AnimalIQuadruped的子类型的特定类型”,又不是“任何同时是AnimalIQuadruped的子类型的类型”

The reason it's difficult to grasp the difference is that in everyday thinking we don't make that distinction explicit. 难以理解差异的原因是,在日常思考中,我们并未明确区分。 If for example you agree to go out for lunch with someone in a restaurant, and they say "any day next week is good for me", you automatically know that means you need to turn up on the same day. 例如,如果您同意与某人在一家餐馆共进午餐,并且他们说“下周的任何一天对我都有好处”,您会自动知道这意味着您需要在同一天上班。 And not that you can go at any time and they'll be there. 并不是说您可以随时去,他们会在那里。

In this case there's no guarantee that the E the caller chooses will definitely be Dog , so your code won't work. 在这种情况下,不能保证呼叫者选择的E肯定是Dog ,因此您的代码将无法工作。

The obvious wrong solution is to specify <E extends Dog> , because it would guarantee that E is a subtype of Dog . 明显的错误解决方案是指定<E extends Dog> ,因为它将保证EDog的子类型。 However this is wrong for the exact same reason, E could be any subtype of Dog , let's say E is a Poodle , so when you create a List<Poodle> , you won't be able to put your new Dog() in there, because it isn't a Poodle . 但是由于完全相同的原因这是错误的, E可以是Dog任何子类型,假设E是一个Poodle ,因此当您创建List<Poodle> ,将无法在其中放置new Dog() ,因为它不是Poodle

The correct bound is <E super Dog> , because that means E is definitely a type that you can cast a Dog instance to. 正确的界限是<E super Dog> ,因为这意味着E绝对是可以将Dog实例强制转换为的类型。 It could be Dog itself, it could be Animal or IQuadruped or even Object . 它可能是Dog本身,可能是AnimalIQuadruped甚至是Object But it guarantees that you can put a Dog in the list. 但它保证您可以在列表中放入“ Dog ”。

The name of this principle is PECS: producer extends, consumer super, and you can read about it here . 该原则的名称是PECS:生产者扩展,消费者超级,您可以在此处阅读。

Generics type erasure is what you are getting. 泛型类型擦除就是您所得到的。 By the time the JVM executes the line where you are adding to the list, the generics is already lost. 当JVM执行要添加到列表中的行时,泛型已经丢失。 To get this to work, you would have to do something like: 要使其正常工作,您必须执行以下操作:

public <E extends Animal & IQuadruped> void testFunction(E param) {
    List<E> list = new ArrayList<E>();
    list.add(param);
}

public void addDog() {
    testFunction(new Dog())
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM