Mikhail Panteleev
Mikhail Panteleev

Reputation: 133

Using generics in ArrayList (Java, "cannot be applied" error)

In my Android Studio project I have simple structure of classes:

public class P{}

public class A extends P{}

public class B extends P{}

And in another class I have a List:

private List<? extends P> data;
private List<A> listA;
private List<B> listB;

But when I try to do that:

data = listA; //it's ok
data.addAll(listB); //it calls error

The second line is red in Android Studio and error is:

addAll(java.util.Collection<capture<? extends com.mydomain.P>>) 
in List cannot be applied to (java.util.List<com.mydomain.subclass.B>)

How can I solve this problem?

Upvotes: 2

Views: 7290

Answers (3)

Braj
Braj

Reputation: 46841

Try this one if you are using ArrayList only.

public class P {}

public class A extends P {}

public class B extends P {}

public class MyList<T extends P> extends ArrayList<P> {
    private static final long serialVersionUID = 1L;
    ...
}

private static MyList<? extends P> data;
private static MyList<A> listA;
private static MyList<B> listB;

public static void main(String[] args) throws IOException {

    data = listA; // it's ok
    data.addAll(listB); // it's ok
}

Upvotes: 1

njzk2
njzk2

Reputation: 39406

When you declare private List<? extends P> data; You require a specific type that extends p for the content of your list, which is not necessary. You can simply use:

private List<P> data;

As any class that extends P (B and A alike) will be accepted.

(That prevent you from assigning data = listA, though)

Upvotes: 5

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280030

When you use a parameterized type like List, the compiler does some type binding and type checking at compilation time.

So with a variable declared as

List<A> listA;

any use of listA will be with the type argument A.

With a variable declared as

List<?> data;

any use of data will be with the type argument ? which is the wildcard, but the actual type is unknown.

Given that it doesn't know the actual type, the compiler can't let you make use of it. The add(E) method of List depends on the type variable. So

List<A> listA = ...;
listA.add(someA);

would be fine since someA is of type A.

Now you may think

List<?> data = listA;
data.add(someA); // theoretically fine

should word, but like this

List<?> data = someMethod();
data.add(someA);

it doesn't. What if the referenced List isn't meant to hold A objects?

The compiler simply can't allow this. That is what type-checking all about with generics.

Upvotes: 3

Related Questions