wood burning stoves*
The moose likes Java in General and the fly likes upper bound wildcard is readonly but lower bound are not Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "upper bound wildcard is readonly but lower bound are not" Watch "upper bound wildcard is readonly but lower bound are not" New topic
Author

upper bound wildcard is readonly but lower bound are not

Kartik Patel
Ranch Hand

Joined: Sep 12, 2005
Posts: 73
Why upper bound wildcard generics make the collection readonly but same not apply for lower bound wildcard collection?

List<? extends Number> l= new ArrayList<Integer>();
Number n1= new Double(1.0);
l.add(n1) // won't compile

List<? super Double> l= new ArrayList<Number>();
Number n1= new Double(1.0);
Double n2= new Double(1.0);
l.add(n1) // won't compile
l.add(n2) // will compile


Chop your own wood, and it will warm you twice. - Henry Ford
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19651
    
  18

With List<? extends Number>, you can't add anything because you don't know which Number subclass you can actually add. Is this list in fact List<Integer>, List<Double>, List<Float>? You don't know! Therefore, you can't add a Double - it might break the rules for the list.

With List<? super Double>, you know that the generic type is a Double or any of its super classes - Number or Object. So let's consider the options:
List<Double> - no problem in adding a Double here
List<Number> - a Double is a Number, so no problem here either
List<Object> - anything is an object, so no problem here either


When retrieving it's the other way around. With List<? extends Number>, you don't know what the type is, except that it is Number or a sub class. Therefore, you can safely assign any element to a Number reference. With List<? super Double>, you don't know what type it actually is; you have three options. You can't assume it's a Double or a Number, so you can only assign it to Object references without explicit casting.


SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6
How To Ask Questions How To Answer Questions
Kartik Patel
Ranch Hand

Joined: Sep 12, 2005
Posts: 73
Originally posted by Rob Prime:


With List<? super Double>, you know that the generic type is a Double or any of its super classes - Number or Object. So let's consider the options:
List<Double> - no problem in adding a Double here
List<Number> - a Double is a Number, so no problem here either
List<Object> - anything is an object, so no problem here either


I think adding List<Number> and List<Object> won't compile in case of List<? super Double>. Only List<Double> will compile. Please try.
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19651
    
  18

I was not talking about adding the lists, but adding a Double to any of these types. In code:

Compiles without a problem.
Kartik Patel
Ranch Hand

Joined: Sep 12, 2005
Posts: 73
I am talking about this. See following tree
Vehicle
Honda Tata
City Civic Indigo Indica

Check this:

class Vehicle {}
class Honda extends Vehicle {}
class Tata extends Vehicle {}
class City extends Honda {}
class Civic extends Honda {}
class Indica extends Tata {}
class Indigo extends Tata {}

List<? super Honda> ls=null;

Honda honda=new Honda();
Civic civic=new Civic();
Vehicle vehicle=new Vehicle();


ls.add(honda); // Fine Honda super Honda
ls.add(civic); // ITS WORKING WHY??? civic is not super of Honda
ls.add(vehicle); // Its not WORKING WHY??? Vehicle super Honda right?


Please suggest..
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19651
    
  18

Originally posted by Kartik Patel:
ls.add(honda); // Fine Honda super Honda
ls.add(civic); // ITS WORKING WHY??? civic is not super of Honda
ls.add(vehicle); // Its not WORKING WHY??? Vehicle super Honda right?

A Civic object will pass the "instanceof Honda" test so that is why you can add elements. You can't prevent this using generics - if a method can accept a Honda object, it can accept a Civic object too. The only thing you could do is checking exact class matching (if (civic.getClass() == Honda.class)).

Now why you cannot add a Vehicle object:
List<? super Honda> means that it could, in fact, be a List<Honda>. It could be a List<Vehicle> as well, but you don't know that. As far as adding goes, it IS a List<Honda>.

If you want to be able to add Vehicles, you need to declare the list to allow Vehicles:
- List<Vehicle>
- List<? super Vehicle>
- List<Object> // equals List<? super Object>

That will still allow Civics and Hondas though.


The super does not means that it accepts only super classes of Honda. It means that the type is Honda or a super class. And as I said before, anywhere you can use a Honda, you can use a Civic.

Similarly, List<? extends Honda> means that the type is Honda or a sub class. Therefore, you know that everything that is stored in it is at least a Honda; it might be a Civic, or an Indigo, you don't know that without runtime checking, but it is still a Honda. But since you don't know that type, you can't add any Honda object to it. Imagine you want to add a Civic but it is in fact a List<Indigo>. So much for your type safe List...


So the rule is as such, for any class X:
List<? super X> can add objects of X or a sub class. You can only retrieve elements as Object though; everything else needs to be cast.
List<? extends X> cannot have anything added at all. You can retrieve elements as X or any super class of X.
List<X> can add objects of X or a sub class. You can retrieve elements as X or any super class of X.


If you don't understand, please (re)read the Generics Trail of the Sun Java tutorial.
Kartik Patel
Ranch Hand

Joined: Sep 12, 2005
Posts: 73
Thanks Rob. The explanation was quite informative.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: upper bound wildcard is readonly but lower bound are not
 
Similar Threads
Generic Question: wildcard with super
Generics doubt
Generics question
Generic question with ?
This code is right or wrong ?