7

In the following code Java, I have created a list nums. I can assign the another list during the declaration. But new items cannot be added except the null. So, does it mean the nums is readonly? Why? Is it possible to add new items in that list?

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);

List<? extends Number> nums = ints;
nums.add(3.14); //Generates error
nums.addAll(ints);  //Generates error

nums.add(null);     //works
System.out.println(nums.get(0));    //works

I have gone through this link. I can't get exact reason.

Community
  • 1
  • 1
Pradip Kharbuja
  • 3,442
  • 6
  • 29
  • 50
  • I dont know, note that nums.add((Number) new Double(3.14)); results in the error: The method add(capture#1-of ? extends Number) in the type List is not applicable for the arguments (Number) – Marcos Vasconcelos Sep 16 '15 at 16:56
  • 1
    See this question: http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs – Natix Sep 16 '15 at 17:11
  • this is a very common misconception; but the conception works in most cases :) – ZhongYu Sep 16 '15 at 17:24
  • Refer to https://docs.oracle.com/javase/tutorial/java/generics/bounded.html for more understanding. – Nirav Patel Sep 16 '15 at 17:27

4 Answers4

7

Is it possible to add new items in that list?

Nope... because that code doesn't know what it's "actually" a list of. Imagine if you could:

List<String> strings = new ArrayList<>();
List<? extends Object> objects = strings; // This is fine
objects.add(new Object()); // Fortunately this *isn't* valid...
System.out.println(strings.get(0).length()); // Or what would this do?

Basically, when you use a wildcard like ? extends T you can only get values out via the API... and when you use a wildcard like ? super T, you can only put the values in via the API - because that's what's safe.

Pradip Kharbuja
  • 3,442
  • 6
  • 29
  • 50
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    @PradipKharbuja: No, not really. The list itself isn't read-only - you could still add to it via `ints`, or remove from it via `nums`. You just can't *add* to `nums` because of type safety. – Jon Skeet Sep 16 '15 at 17:06
3

No, it's not read-only... even though that is typically the intention.

Given a List<? extends Number> object, the compiler converts its type to List<X> where X is an unknown subtype of Number. Therefore, the object does have an add(X) method. We can call the method with an X argument... for example, null.

And since get() returns X, we could also call add() with a value from get() .... Directly invoking list.add(list.get(i)) won't work, even though it makes sense. We will need a little helper.

The classic example is Collections.reverse(List<? extends Object> list). This method will modify the list, despite the wildcard.

You can also call mutating methods like clear(), of course, on any list.


That being said, wildcard is indeed mainly for use-site variance, and most often, it conveys the intention from the API designer of whether a type-parameter is intended for in or out. For example, by declaring List<? super/extends Foo>, the API expresses that it intends to inject T in to, or, get T out of, the list.

It is a misconception that wildcard makes read/write-only. But this misconception works in most use cases. And the more people having this misconception, the more it becomes a convention...

see my article on wildcard - http://bayou.io/draft/Capturing_Wildcards.html

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
0

It's helps when you think of List<? extends Number> nums as a List of some type of thing that extends Number, but you can't be sure what. As such, everything you do with nums needs to be able to done to such a thing.

Adding null works because null can be cast into absolutely anything. Everything else you try to add will fail, because the compiler can't be 100% certain that the thing you're adding extends the thing the list is made of.

Instead of List<? extends Number> nums do List<Number> nums, because you can still put in anything that extends Number.

? doesn't mean "anything", it is closer to meaning "some specific but unknown".

Captain Man
  • 6,997
  • 6
  • 48
  • 74
-1

Generics is compile time only.

So Compiler will decide what is actual type we are going to use.

List<? extends Number>

It means we are not sure what actual type of the object.

So Compiler not make sure what is the actual type that list have.

Siva Kumar
  • 1,983
  • 3
  • 14
  • 26