How to Add to List≪? Extends Number≫ Data Structures

How can I add to List<? extends Number> data structures?

Sorry, but you can't.

The wildcard declaration of List<? extends Number> foo3 means that the variable foo3 can hold any value from a family of types (rather than any value of a specific type). It means that any of these are legal assignments:

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

So, given this, what type of object could you add to List foo3 that would be legal after any of the above possible ArrayList assignments:

  • You can't add an Integer because foo3 could be pointing at a List<Double>.
  • You can't add a Double because foo3 could be pointing at a List<Integer>.
  • You can't add a Number because foo3 could be pointing at a List<Integer>.

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.

The reverse logic applies to super, e.g. List<? super T>. These are legal:

List<? super Number> foo3 = new ArrayList<Number>(); // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>(); // Object is a "super" of Number

You can't read the specific type T (e.g. Number) from List<? super T> because you can't guarantee what kind of List it is really pointing to. The only "guarantee" you have is you are able to add a value of type T (or any subclass of T) without violating the integrity of the list being pointed to.


The perfect example of this is the signature for Collections.copy():

public static <T> void copy(List<? super T> dest, List<? extends T> src)

Notice how the src list declaration uses extends to allow me to pass any List from a family of related List types and still guarantee it will produce values of type T or subclasses of T. But you cannot add to the src list.

The dest list declaration uses super to allow me to pass any List from a family of related List types and still guarantee I can write a value of a specific type T to that list. But it cannot be guaranteed to read the values of specific type T if I read from the list.

So now, thanks to generics wildcards, I can do any of these calls with that single method:

// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double>());

Consider this confusing and very wide code to exercise your brain. The commented out lines are illegal and the reason why is stated to the extreme right of the line (need to scroll to see some of them):

  List<Number> listNumber_ListNumber  = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>(); // error - can assign only exactly <Number>
//List<Number> listNumber_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Number>

List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>();
List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>();

List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>(); // error - Integer is not superclass of Number
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>(); // error - Double is not superclass of Number


//List<Integer> listInteger_ListNumber = new ArrayList<Number>(); // error - can assign only exactly <Integer>
List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Integer>

//List<? extends Integer> listExtendsInteger_ListNumber = new ArrayList<Number>(); // error - Number is not a subclass of Integer
List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a subclass of Integer

List<? super Integer> listSuperInteger_ListNumber = new ArrayList<Number>();
List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a superclass of Integer


listNumber_ListNumber.add(3); // ok - allowed to add Integer to exactly List<Number>

// These next 3 are compile errors for the same reason:
// You don't know what kind of List<T> is really
// being referenced - it may not be able to hold an Integer.
// You can't add anything (not Object, Number, Integer,
// nor Double) to List<? extends Number>
//listExtendsNumber_ListNumber.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Number>
//listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer>
//listExtendsNumber_ListDouble.add(3); // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double>

listSuperNumber_ListNumber.add(3); // ok - allowed to add Integer to List<Number> or List<Object>

listInteger_ListInteger.add(3); // ok - allowed to add Integer to exactly List<Integer> (duh)

// This fails for same reason above - you can't
// guarantee what kind of List the var is really
// pointing to
//listExtendsInteger_ListInteger.add(3); // error - can't add Integer to *possible* List<X> that is only allowed to hold X's

listSuperInteger_ListNumber.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
listSuperInteger_ListInteger.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>

Why in java generics List<Integer> is a subtype of List<? extends Integer>?

Why in java generics List<Integer> is a subtype of List<? extends Integer>?

Because otherwise you wouldn't be able to do things such as:

List<Integer> list1 = new ArrayList<>();
List<? extends Integer> list2 = list1;

Personally, I would find the above resulting in an error to be the conter-intuitive scenario. When you have List<? extends Integer> all that's saying is that the List may contain Integer, some subtype of Integer1, or a mixture of Integer's subtypes1. A List<Integer> certainly meets those requirements.

The argument for List<? super Number> being a subtype of List<? super Integer> is very similar. If that wasn't the case then you couldn't do the following:

List<? super Number> list1 = new ArrayList<>();
List<? super Integer> list2 = list1;

All that List<? super Integer> means is the List is capable of consuming an object of type Integer or some supertype of Integer. A List<? super Number> meets those requirements.

Here are some links which may prove useful:

  • What is PECS (Producer Extends Consumer Super)?
  • Difference between <? super T> and <? extends T> in Java
  • How can I add to List<? extends Number> data structures?

I recommend browsing the linked/related sections of the above Q&As as well.


1. Saying "subtype of Integer" may be confusing since the class is final but hopefully it still makes sense.

Java Generic with ArrayList <? extends A> add element

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

What is meaning of <E extends Number> List<? super E> return type of method in java

For this generic method the return type is determined by the argument type. The argument can be List<Number> and List of subtypes of Number. Eg if you call process with this arg

List<Integer> list = ...
process(list)

the return type will be List<? super Integer>. Generic type with ? super can be assigned only to generic type with ? super

List<Integer> input = null;
List<? super Integer> output = process(input);

it cannot be List<Number> or List<Object> because they allow writing subclasses of generic parameter. Eg List<Number> list allows list.add(1L);

Correct answer is G.

Add parent object to List<? extends Parent> - Java

You cannot add anything to a List<? extends Animal>, ever. List<? extends Animal> means "a list of I-don't-know-what-but-something-that-extends-Animal", which could be a List<Animal> or a List<Cat>.

If you could, this code would compile:



List dogs = new ArrayList();
List animals = dogs;
animals.add(new Cat());
Dog dog = dogs.get(0);

You can, however, change List<? extends Animal> to List<Animal> which seems to be what you want here.

Why java lets me add a Box(Raw type) to a List<Box<? extends Item>>

This code does generate an unchecked conversion warning, as to why its permitted, from Angelika Langer's blog

Why are raw types permitted?

To facilitate interfacing with
non-generic (legacy) code. Raw types are permitted in the language
predominantly to facilitate interfacing with non-generic (legacy)
code.

If, for instance, you have a non-generic legacy method that takes a
List as an argument, you can pass a parameterized type such as
List<String> to that method. Conversely, if you have a method that
returns a List , you can assign the result to a reference variable of
type List<String> , provided you know for some reason that the
returned list really is a list of strings.

Your answer lies in Conversely, if you have a method that returns a List , you can assign the result to a reference variable of type List<String>. In your case you might have a legacy method that returns a Box

 // Legacy code
private Box getBox(){
// returns a Box which satisfy the Box<? extends Bakery>
}

even though the returned result might satisfy the constraint Box<? extends Bakery>, there is no way to be completely sure, so you are allowed to add that box to your list

how to understand List<? extends Number> arr = Arrays.asList(1,2,3.1f,4.1d)

That code is not "adding" an element to a List<? extends Number>. Adding an element into a List<? extends Number> looks something like:

arr.add(1);

which doesn't compile as you'd expect.

What your code is doing is creating a list containing 1, 2, 3.1, and 4.1, using Arrays.asList. Then you assign that list to the variable arr. You never added to arr.

When we say "you can only add null to a list of type List<? extends Number>", we really only mean that if you have a variable of type List<? extends Number> (arr in this case), you can only pass null to its add method (or any other method that accepts its generic type parameter).

It does not mean that there is no absolutely no way to add elements to the list object referenced by that variable. You just can't add to it by directly calling the add method.

For example,

ArrayList<Integer> ints = new ArrayList<>();
ArrayList<? extends Number> numbers = ints; // now numbers and ints refer to the same list
System.out.println(numbers); // prints []
ints.add(1);
System.out.println(numbers); // prints [1]


Related Topics



Leave a reply



Submit