Java Generic with ArrayList <? extends A> add element

試著忘記壹切 提交于 2019-12-28 04:22:05

问题


I have classes A, B, C and D where B extends A, C extends A and D extends A.

I have the following ArrayLists each with a few elements in them:

ArrayList<B> b;
ArrayList<? extends A> mix = b;

I intended for the variable mix to contain elements of type B, C or D. I tried to add an element of type C into mix like this:

mix.add(anElementOfTypeC);

But the IDE doesn't allow me to do so and it says:

anElementOfTypeC cannot be converted to CAP#1 by method of invocation conversion where CAP#1 is a fresh type-variable: CAP#1 extends A from capture of ? extends A

Did I use the <? extends A> correctly? How can I resolve this?


回答1:


ArrayList<? extends A> means an ArrayList of some unknown type that extends A.
That type might not be C, so you can't add a C to the ArrayList.

In fact, since you don't know what the ArrayList is supposed to contain, you can't add anything to the ArrayList.

If you want an ArrayList that can hold any class that inherits A, use a ArrayList<A>.




回答2:


It is not possible to add elements in collection that uses ? extends.

ArrayList<? extends A> means that this is an ArrayList of type (exactly one type) that extends A. So you can be sure, that when you call get method, you'll get something that is A. But you can't add something because you don't know what exactly contains ArrayList.




回答3:


Did I use the <? extends A> correctly?

List<? extends A> list; means that the 'list' refers to an object implemented interface List, and the list can hold elements inherited from class A (including A). In other words the following statements are correct:

List<? extends A> listA1 = new ArrayList<A>();
List<? extends A> listB1 = new ArrayList<B>();
List<? extends A> listC1 = new ArrayList<C>();
List<? extends A> listD1 = new ArrayList<D>();

Java generics are a compile-time strong type checking. The compiler uses generics to make sure that your code doesn't add the wrong objects into a collection.

You tried to add C in ArrayList<B>

listB1.add(new C());

If it were allowed the object ArrayList<B> would contain different object types (B,C).
That is why the reference listB1 works in 'read-only' mode. Additionally you could take a look at this answer.

how to resolve this?

List<A> list = new ArrayList<A>();



回答4:


You could just declare:

ArrayList<A> mix = new ArrayList<A>();

You can add any element of class A or any of its subclasses into such a list. It is just that when you get from that list, you will only be able to call methods available on A.

Note that A is not limited to being a "full fledged" class: it can be an abstract class or even an interface.




回答5:


You can create the array list of super class type. so you can do this.

ArrayList<A> arrayList=new ArrayList<A>();



回答6:


Look at this example and choose as per your requirement

package com.generic;

import java.util.ArrayList;

public class SuperExtendTest {

    /**
     * @param args
     */
    public static void main(String[] args) {

    }
    public void test() throws Exception {
        ArrayList<Parent> parents=new ArrayList<>();
        parents.add(new Parent());
        parents.add(new Child());
        //parents.add(new GrandParent()); Not allowed

        ArrayList<Parent> p=new ArrayList<>();
        ArrayList<Child> c=new ArrayList<>();
        ArrayList<GrandParent> gp=new ArrayList<>();

        testExtendP(p);
        //testExtendP(c); Not allowed only super type allowed no child
        testExtendP(gp);

        testExtends(c);
        testExtends(p);
        //testExtends(gp); Not allowed because GrantParent does not extends Parent
    }

    /**
     * This Method allowed get operations for Parent 
     * No add 
     * 
     */
    public void testExtends(ArrayList<? extends Parent> list) throws Exception {
    /*  list.add(new Child());
        list.add(new Parent());
        list.add(new GrandParent());
        // can not add
        */
        Child c=(Child) list.get(0);
        Parent parent=list.get(0);
        GrandParent gp=list.get(0);
        /**
         * Unsafe collection way
         */
        ArrayList list2=new ArrayList();
        list.addAll(list2);
    }

    /**
     * This Method allowed add operations for Parent and it's sub types and on get it gives Object type 
     * 
     */
    public void testExtendP(ArrayList<? super Parent> list) throws Exception {
        list.add(new Child());
        list.add(new Parent());
        //list.add(new GrandParent());
        /*can not add because GrandParent can not be converted to Parent type
         * 
         * The method add(capture#3-of ? super Parent) in the type ArrayList<capture#3-of ? super Parent> is not applicable for the arguments (GrandParent)
         * 
         */

        Child c=(Child) list.get(0);
        Parent parent=(Parent) list.get(0);
        GrandParent gp=(GrandParent) list.get(0);
        Object obj=list.get(0);

        /**
         * Unsafe collection way
         */
        ArrayList list2=new ArrayList();
        list.addAll(list2);
    }

    /**
     * This Method allowed all operations for Parent and it's sub types 
     * 
     */
    public void testDirect(ArrayList<Parent> list) throws Exception {
        list.add(new Child());
        list.add(new Parent());
        //list.add(new GrandParent()); 
        /*
         * Can not add GrandParent (Normal generic rule)
         */
    }

}
class GrandParent{

}

class Parent extends GrandParent{

}
class Child extends Parent{

}


来源:https://stackoverflow.com/questions/14306166/java-generic-with-arraylist-extends-a-add-element

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!