Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"? extends ParentClass" makes Read only?

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.

like image 583
Pradip Kharbuja Avatar asked Sep 16 '15 16:09

Pradip Kharbuja


2 Answers

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.

like image 121
Jon Skeet Avatar answered Nov 13 '22 23:11

Jon Skeet


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

like image 34
ZhongYu Avatar answered Nov 14 '22 00:11

ZhongYu