2

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?

Mikhail Panteleev
  • 133
  • 1
  • 3
  • 12

3 Answers3

5

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)

njzk2
  • 38,969
  • 7
  • 69
  • 107
3

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.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
1

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
}
Braj
  • 46,415
  • 5
  • 60
  • 76
  • Careful, this isn't the same thing. It would be if you had `ArrayList` rather than `

    `.

    – Sotirios Delimanolis Apr 10 '14 at 19:50
  • but `T extends P`. What is the issue in it. – Braj Apr 10 '14 at 19:52
  • But I want to know what the issue in this way? – Braj Apr 10 '14 at 19:53
  • In their example, the `addAll` method depends on the type variable `E` declared in `List`. The compiler binds `? extends P` to that type variable when they declare `List extends P>`. In your example, you declare a different type `MyList` with a type variable `T`, but the `addAll` method inherited from `ArrayList` depends on `P`, not on `T`. So in your declaration of `MyList extends P>` and then `data.addAll`, the `addAll` isn't looking at `?`, it's looking at `P`. – Sotirios Delimanolis Apr 10 '14 at 19:55
  • Its giving me compilation error if I use `ArrayList`. `The method addAll(Collection extends capture#2-of ? extends TestDemo.P>) in the type ArrayList is not applicable for the arguments (TestDemo.MyList)` – Braj Apr 10 '14 at 19:55
  • Exactly, that would be the same thing OP gets. You've changed the situation. You're no longer explaining OP's problem, but a different one. – Sotirios Delimanolis Apr 10 '14 at 19:56
  • I think there is no issue in using `ArrayList

    ` because `T extends P`.

    – Braj Apr 10 '14 at 20:07
  • I'm not saying there's an issue. Your code will compile fine. But it is not a good example or demonstration of what OP is doing nor does it explain why they get an exception. It's a completely different situation. – Sotirios Delimanolis Apr 10 '14 at 20:08