8
public void addAllAnimals(ArrayList<? extends Animal> animalLikeList){

 // I need to add animal objects (eg Dog, Cat that extends Animal) to animalLikeList.

}

我知道它不允许直接添加,因为它? extends Animal代表Animal.

我的问题是:没有任何方式(间接方式)add或对象addAll的子类型吗?AnimalAnimalanimalLikeList

4

6 回答 6

9

不,没有直接的合法方式(除了不安全的类型转换)。您只能将元素添加到用 声明的通用集合super,而不是extends使用 Josh Bloch 在Effective Java, 2nd Edition , Item 28中推广的首字母缩写词PECS(Producer - Extends,Consumer - Super)可能更容易记住这一点。

事实上,你所追求的似乎并没有直接意义。AList<? extends Animal>可以是例如 aList<Dog>或 a List<Cat>。前者只能接受Dog元素,后者只能接受Cats。而且由于您不能在 Java 中实例化通用(不可具体化)类型,因此您必须在运行时知道您正在处理一个狗列表,因此您只尝试将狗添加到其中(猫反之亦然)。这意味着您不能在本地和静态地创建要添加的对象 - 您也必须以通用方式获取它们,而且以允许编译器确保每次都匹配具体类型的方式。最简单的方法是将元素作为通用参数传递。因此,这样做是可能且安全的:

public <E extends Animal> void addAllAnimals(List<E> animalLikeList, E animal) {
    animalLikeList.add(animal);
}

List<Dog> dogs = new ArrayList<Dog>();
List<Cat> cats = new ArrayList<Cat>();

addAllAnimals(dogs, new Dog());
addAllAnimals(cats, new Cat());

请注意,此方法是泛型的,带有命名类型参数,可确保列表的实际泛型类型与要添加到其中的元素类型相同。

您可以简单地将E参数替换为 aCollection<E>以一次添加多个对象。

于 2012-06-20T12:46:28.573 回答
4

我的问题是:是否有任何方式(间接方式)向 animalLikeList 添加或添加 Animal 或 Animal 对象的 SubType?

并非没有更改签名,并且有充分的理由。假设您想Dog向该列表添加值......但假设它在逻辑上是一个猫列表:

ArrayList<Cat> cats = new ArrayList<Cat>();
addAllAnimals(cats);

您不应该将 a 添加Dog到a ,对ArrayList<Cat>吗?

如果您希望能够将任何类型的动物添加到列表中,您需要:

public void addAllAnimals(ArrayList<Animal> animalLikeList) {

或者

public void addAllAnimals(ArrayList<? super Animal> animalLikeList) {
于 2012-06-20T12:46:21.880 回答
1

为什么不简单地更改方法签名以使用不变类型参数?

public void addAllAnimals(ArrayList<Animal> animalLikeList){
   animalLinkedList.add(new Dog());
   animalLinkedList.add(new Cat());

}

它应该可以正常工作,并且通过使用不变的类型参数,您将被允许从列表中读取或写入列表,并且根据子类型多态性的规则,它可以包含您想要的任何种类的动物。

与其尝试传递狗列表或猫列表,不如将动物列表传递给该方法。

于 2012-06-20T13:01:53.617 回答
0
ArraList<anything extends animal> list= new ArrayList<anything extends animal>();


addAllAnimals(list);

这是完全有效的。您的方法addAllAnimals将接受任何声明包含 Animal 的任何子类型的 arrayList。

对于添加对象/列表,您可以添加任何对象/列表动物的子类型。

于 2012-06-20T12:49:08.613 回答
0

不是以类型安全的方式...

一种想法是将签名更改为:

public static <T extends Animal> void addAllAnimals(ArrayList<? super T> list){}

您可以将 T 或 T 的子类型添加到 T 列表中...

于 2012-06-20T12:56:19.380 回答
0

您可以使用非通用方式在通用集合中添加所有

public void testExtends(ArrayList<? extends Parent> list) throws Exception {
    /*  list.add(new Child());
        list.add(new Parent());
        list.add(new GrandParent());
        // can not add
        */
        /**
         * Unsafe collection way
         */
        ArrayList list2=new ArrayList();
        list.addAll(list2);
    }
于 2014-05-20T12:13:03.440 回答