vda8888
vda8888

Reputation: 707

Java Generic with ArrayList <? extends A> add element

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?

Upvotes: 34

Views: 46435

Answers (6)

Dmitry Zaytsev
Dmitry Zaytsev

Reputation: 23962

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 the ArrayList contains.

Upvotes: 12

Ankit Katiyar
Ankit Katiyar

Reputation: 3001

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{

}

Upvotes: 0

Oleks
Oleks

Reputation: 1051

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

Upvotes: 7

sumit sharma
sumit sharma

Reputation: 1057

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

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

Upvotes: 0

fge
fge

Reputation: 121710

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.

Upvotes: 3

SLaks
SLaks

Reputation: 887453

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>.

Upvotes: 46

Related Questions