0

Why can't I add the a object to the collection? Since the class B is something that extends A.

import java.util.*;

public class TestGeneric
{
  public static void main(String[] args)
  {
    Collection<? extends A> collection = new ArrayList<A>();
    A a = new B();
    collection.add(a);
  }

  private static class B implements A {
    public int getValue() { return 0; }
  }
}

interface A { int getValue(); }
npeder
  • 788
  • 10
  • 26
  • Possible duplicate of [Can't add value to the Java collection with wildcard generic type](http://stackoverflow.com/questions/3716920/cant-add-value-to-the-java-collection-with-wildcard-generic-type). See also: [Java Generics: What is PECS?](http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs) – Paul Bellora Sep 24 '13 at 14:18

4 Answers4

4

Because of the following reason:

Collection<? extends A> coll = new ArrayList<C>(); // C extends A

coll.add(new B()); // B extends A, but doesn't extend C. Oops.

However, since the compiler knows that coll only has elements that extends A, you can still retrieve them as As.

A myA = coll.get();  // No problem, it might be B or C, but they both extend A
Kayaman
  • 72,141
  • 5
  • 83
  • 121
3

Short and simple explanation:

<? extends A> means: some specific but unknown type that extends A. Could be A itself or any of its subtypes. Therefore, you cannot insert any element in this collection: the compiler can't know what type would be legal for parameters for the add(object) method.

herman
  • 11,740
  • 5
  • 47
  • 58
2

Keep in mind: Provider extends consumer super (also known as PECS)

You want to put things into the collection, so the collection is a consumer.

    Collection<? super A> collection = new ArrayList<A>();

From this answer

Case 2: You want to add things to the collection. Then the list is a consumer, so you should use a Collection<? super Thing>.

The reasoning here is that unlike Collection<? extends Thing>, Collection<? super Thing> can always hold a Thing no matter what the actual parameterized type is. Here you don't care what is already in the list as long as it will allow a Thing to be added; this is what ? super Thing guarantees.

Community
  • 1
  • 1
ppeterka
  • 20,583
  • 6
  • 63
  • 78
1

if you have <? extends A> then at this point compiler does not know what is the subclass of A that is getting used. So it's not safe to add any object to collection except null.

You can't add any object to List<? extends T> because you can't guarantee what kind of List it is really pointing to, so you can't guarantee that the object is allowed in that List. The only "guarantee" is that you can only read from it and you'll get a T or subclass of T.

List<? extends Number> can be implemented by three:

List<? extends Number> list = new ArrayList<Number>(); // Number "extends" Number List<? extends Number> list = new ArrayList<Integer>(); // Integer extends Number List<? extends Number> list = new ArrayList<Double>(); // Double extends Number

So if it is new ArrayList<Double>() and you are adding integer so it's an error, so it's safe for compiler to restrict the access to only reading no adding.

And adding is also safe because we know the parent class hence we can assign any child class to parent class reference as below:

Parent p = new Child(); //this is safe

hence in List<? extends Number> we know all the elements inside the collection are somehow extending Number hence we can read it because we can assign an instance of child class to parent class reference.

Trying
  • 14,004
  • 9
  • 70
  • 110