将对象添加到“?extends”类型的通用集合中

时间:2012-06-20 12:42:34

标签: java generics collections

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

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

}

我知道它不允许直接添加,因为? extends Animal代表Animal的未知子类型。

我的问题是:addaddAll AnimalAnimal对象的子类型是否有任何方式(间接方式)到animalLikeList

6 个答案:

答案 0 :(得分:8)

不,没有直接合法的方式(除了不安全的类型演员)。您只能将元素添加到使用super声明的通用集合,而不是extends。这可能更容易记住,首字母缩略词 PECS (制作人 - 扩展,消费者 - 超级),由Josh Bloch在 Effective Java,2nd Edition ,第28项中推广。

事实上,你似乎追求的似乎没有直接意义。 List<? extends Animal>可以是例如一个List<Dog>List<Cat>。前者只能接受Dog元素,后者仅接受Cat个元素。由于您无法在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简单地替换Collection<E>参数,以便一次添加多个对象。

答案 1 :(得分:4)

  

我的问题是:是否有任何方式(间接方式)向AnimalLikeList添加或添加动物对象的Animal或子类型?

不是没有改变签名,而且有充分的理由。假设您要将Dog值添加到该列表中......但假设它在逻辑上是猫的列表:

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

您应该无法向Dog添加ArrayList<Cat>吗?

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

public void addAllAnimals(ArrayList<Animal> animalLikeList) {

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

答案 2 :(得分:1)

为什么不直接更改方法签名以使用不变的类型参数?

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

}

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

不要试图通过狗列表或猫列表,而是将动物列表传递给方法。

答案 3 :(得分:0)

ArraList<anything extends animal> list= new ArrayList<anything extends animal>();


addAllAnimals(list);

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

并且为了添加一个对象/ List,你可以在任何对象/列表中找到Animal的哪个子类型。

答案 4 :(得分:0)

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

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

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

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

列表中

答案 5 :(得分:0)

您可以在通用集合中使用非通用方法addAll

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);
    }