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?

2
  • The compiler can't let you add any type to a list it doesn't know the type of. Basically, if you don't know the type, ie. you have ?, you can't use that type. Commented Apr 10, 2014 at 19:34
  • PECS Commented Apr 10, 2014 at 19:44

3 Answers 3

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)

Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

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
}

8 Comments

Careful, this isn't the same thing. It would be if you had ArrayList<T> rather than <P>.
but T extends P. What is the issue in it.
But I want to know what the issue in this way?
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.
Its giving me compilation error if I use ArrayList<T>. The method addAll(Collection<? extends capture#2-of ? extends TestDemo.P>) in the type ArrayList<capture#2-of ? extends TestDemo.P> is not applicable for the arguments (TestDemo.MyList<TestDemo.B>)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.