"? extends ParentClass" makes Read only?
Asked Answered
R

4

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.

Rood answered 16/9, 2015 at 16:53 Comment(4)
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<capture#1-of ? extends Number> is not applicable for the arguments (Number)Lavena
See this question: https://mcmap.net/q/15314/-what-is-pecs-producer-extends-consumer-superSparrowgrass
this is a very common misconception; but the conception works in most cases :)Gnarl
Refer to docs.oracle.com/javase/tutorial/java/generics/bounded.html for more understanding.Tort
P
8

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.

Predisposition answered 16/9, 2015 at 16:57 Comment(1)
@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.Predisposition
G
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

Gnarl answered 16/9, 2015 at 17:7 Comment(0)
I
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".

Interface answered 16/9, 2015 at 17:41 Comment(0)
E
-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.

Ethelethelbert answered 16/9, 2015 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.