wood burning stoves 2.0*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes Generics - super Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Java 8 in Action this week in the Java 8 forum!
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "Generics - super" Watch "Generics - super" New topic
Author

Generics - super

Paul Kemp
Ranch Hand

Joined: Dec 03, 2008
Posts: 35
Using Generics, the type of the variable declaration must match the object type.



But the compiler is OK with this:



Why does the compiler accept this notation? Could this List ever been anything other than type Horse? If the object type must be specified, surely the List type has to be the same?
Santiago Bravo
Ranch Hand

Joined: Jul 25, 2008
Posts: 226
Originally posted by Paul Kemp:
....

But the compiler is OK with this:



Why does the compiler accept this notation? Could this List ever been anything other than type Horse? If the object type must be specified, surely the List type has to be the same?



Hi Paul,

The above code is saying that you can take any type which is Horse and any SUPERCLASS. So Horse, Animal and Object can be accepted.

If you had said something like:



Then this means any Horse or subclass of Horse is accepted.

If you do not use any wild card syntax then the type of object must match:




Santiago
My Path to SCJP Certification My Path to SCWCD Certification
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18141
    
  39



This is *not* allowed because an ArrayList<Horse> can't be treated as a List<Animal>... for example...

You can add a Dog, Cat, Chicken, etc., to a List<Animal>, as they are all animal types. However, you can't add any of those animal types to an ArrayList<Horse>.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
Paul Kemp
Ranch Hand

Joined: Dec 03, 2008
Posts: 35
Yes, I understand what you're saying. But you say:

The above code is saying that you can take any type which is Horse and any SUPERCLASS. So Horse, Animal and Object can be accepted.


How?



If I have defined new ArrayList<Horse>(); how can it take anything else?
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18141
    
  39


List<? super Horse> myList = new ArrayList<Horse>();

The above code is saying that you can take any type which is Horse and any SUPERCLASS. So Horse, Animal and Object can be accepted.



No... This is *not* true. The code is saying that it is of an unknown type, that happens to be a horse type or a super of a horse type.

If you try to iterate through the list, the element type return is an Object type, as it doesn't know what type to return.

Furthermore, if you want to add items to the list, you must add horse types, or objects which are subclasses of horse types, as that is the only way to guarrantee the correct type, no matter what super type it is supposed to be.

Henry
Punit Singh
Ranch Hand

Joined: Oct 16, 2008
Posts: 952


no no it's not like that.
you cannot add new Animal().
The statement says you can assign list of any Horse Object or its super class object.

means

List<? super Horse> myList = new ArrayList<Horse>();
List<? super Horse> myList = new ArrayList<Animal>();
List<? super Horse> myList = new ArrayList<Object>();



and you cannot assign list of any horse subclass or any sibling class
List<? super Horse> myList = new ArrayList<WhiteHorse>();//wrong
List<? super Horse> myList = new ArrayList<Dog>();


this will guarantee that your list will contain only Horse object or its subclass objects, not any sibling class object.
[ December 09, 2008: Message edited by: Punit Singh ]

SCJP 6
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18141
    
  39

If you had said something like:

List<? extends Horse> myList = new ArrayList<Horse>();

Then this means any Horse or subclass of Horse is accepted.



This also needs some clarification. In this case, the list is holding some unknown type, which happens to extend the horse type. If you iterate through the list, you will get a horse type, as all classes that extend a horse IS-A horse.

You can *not* add any items to this list. The reason is that you don't know what type it is, and unlike the previous post, there is no type that is all possible types that extend horse.

Henry
Paul Kemp
Ranch Hand

Joined: Dec 03, 2008
Posts: 35
Not sure if I get it to be honest.

Are these bits of code actually the same? They both allow polymorphism on subclasses of Horse...

Brian Legg
Ranch Hand

Joined: Nov 07, 2008
Posts: 488
I have read the K&B chapter on Generics 3 times, read 3 different tutorials on Generics, and done plenty of playing around code...

and I am completely lost when it comes to Generics. I do not understand them at all when combined with polymorphism, collections, and wildcards all at once.

If anyone knows any guides that are VERY simple... like the "around the campfire" stories. A guide that tells a story in a way that makes since. Please post them here as this is a very important topic that I really want to fully grasp.

TY


SCJA
~Currently preparing for SCJP6
Punit Singh
Ranch Hand

Joined: Oct 16, 2008
Posts: 952
for ex:

public void addAnimal(List<? super Dog> animals) {
animals.add(new Dog()); // adding is sometimes OK with super
}
public static void main(String[] args) {
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Dog());
AnimalDoctorGeneric doc = new AnimalDoctorGeneric();
doc.addAnimal(animals); // passing an Animal List
}


Take this code. Here in addAnimal() method we are adding Dog objects.
but accepting any list that containg Dog or any superclass.

So if we call addAnimal(ArrayList<Animal>()), then we can add Dog object in this list as Dog extends Animal.

Now think another case: change the addAnimal() method

public void addAnimal(List<Animal> animals) {
animals.add(new Dog()); // adding is sometimes OK with super
}
and call it:
addAnimal(new ArrayList<Cat> ) ;



Suppose Java compiler had made List<Animal> to accept ArrayList<Cat> then what will happen?

animals.add(new Dog());


we will add Dog object in a Cat list. And generics is only compile time checking. After that for jvm it is like non-generics code.
JVM cannot catch that we are adding Dog object in Cat list.

for array
Animal[] catArr=new Cat[5];
catArr[0]=new Dog();
Array has both compile time checking and runtime checking, here compiler will allow this as catArr is Animal array.
But at runtime JVM will check that the actual array Object type is Cat and it will throw ArrayStoreException.

But for generics only compile time checking is performed, there is no runtime checking. So compiler will not allow any case that allow to add
List<Dog> to have Cat Object.

I think this will help you.
[ December 09, 2008: Message edited by: Punit Singh ]
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18141
    
  39

Are these bits of code actually the same? They both allow polymorphism on subclasses of Horse...

List<Horse> myList = new ArrayList<Horse>();
myList.add(new ShireHorse());

List<? super Horse>myList2 = new ArrayList<Horse>();
myList2.add(new ShireHorse());


Functionally, both code snippets are effectively the same. However, there are differences. Try to iterate through each list. And try to use the lists themselves.

You can easily tell that they are not the same by assigning them to each other...

myList2 = myList; // Okay
myList = myList2; // Not Okay

Henry
Paul Kemp
Ranch Hand

Joined: Dec 03, 2008
Posts: 35
OK. The difference between the two is



Fair Enough.

So the code



on the left hand side of the = is really saying, that myList2 could be of type Horse, Animal, Mammal, Object, the compiler doesn't know, so long as it is above Horse in the hierarchy we're ok, so to play safe we will return type Object here.

Meanwhile on the right hand side of the =, myList2 could contain type Horse, ShireHorse, MyLittlePony, etc, but nothing above Horse in the scheme of things.

So one final question on this if I may...




The code above works OK. In fact, I can replace new ArrayList<Animal>(); with new ArrayList<Object>; new ArrayList<Horse>; and they all compile, so what is the significance of my choice of object on the right-hand side of the equals...? Especially if List<? super ShireHorse>myList2 returns Objects anyway....
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18141
    
  39

First, I must state that the usage in this topic is not common (or supposed to be common). It is actually quite silly to declare a collection, and assign it to a reference with wildcards. Why would you purposely use wildcards, when you know exactly what the collection is?

As an example, a more common usage of wildcards is in the parameter of a method. In this case, you really don't know what is being passed, but you do know that it is a super of a particular class.

So one final question on this if I may...

List<? super ShireHorse>myList2 = new ArrayList<Animal>();
myList2.add(new ShireHorse());

The code above works OK. In fact, I can replace new ArrayList<Animal>(); with new ArrayList<Object>; new ArrayList<Horse>; and they all compile, so what is the significance of my choice of object on the right-hand side of the equals...?


Of course they all compile, the actually type on the right hand side, fits the criteria of the type on the left hand side. As for "the significance of [your] choice of object on the right-hand side of the equals", you do know that they behave differently right?

Especially if List<? super ShireHorse>myList2 returns Objects anyway....


Not sure what you are asking here... Just because a List<? super ShireHorse> returns Objects when iterating, doesn't make it a List<Object> type. You can place Dog objects into a List<Object> -- which you can't do in a List<? super ShireHorse>.

Or are you thinking there is another way to declare it?

Henry
[ December 09, 2008: Message edited by: Henry Wong ]
Paul Kemp
Ranch Hand

Joined: Dec 03, 2008
Posts: 35
Why would you purposely use wildcards, when you know exactly what the collection is?


My question exactly!! In fact, that was my original question in this thread, as below.

Why does the compiler accept this notation? Could this List ever be anything other than type Horse?


Why does the compiler accept this notation at all? Why doesn't it just say, come on, you know what the collection type is, you just told me?

As for the rest of it, everything is clear, thanks.
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18141
    
  39

Originally posted by Paul Kemp:

Why does the compiler accept this notation at all? Why doesn't it just say, come on, you know what the collection type is, you just told me?



You are taking my response out of context. I actually explain why in the sentence that you didn't quote. The compiler allows this notation because there are cases, where it doesn't know what type the collection is... Take an example from this very topic.



This method is written to handle a list of elements, of an unknown type that is a super of Dog. In this case, you actually do not know what types your method will be called with. But you do know that the compiler will type check it, to make sure it is not called with a list of Strings, or anything else that is not a super class of Dog.

Henry
[ December 09, 2008: Message edited by: Henry Wong ]
Paul Kemp
Ranch Hand

Joined: Dec 03, 2008
Posts: 35
Henry, I understand that a method call of the type you describe would be useful in a polymorphic context, I just don't understand why whoever wrote the compiler for Generics would allow the <? super > syntax specifically in the case where you are instantiating a class using the *new* operator,i.e, my original post. This is because a similar example is in the K&B book. I wondered if its use in the specific case I mentioned (not in the method calls you describe which are also described in the K&B book) had any use at all that I couldn't comprehend.
Punit Singh
Ranch Hand

Joined: Oct 16, 2008
Posts: 952
Paul if you comprehend ArrayStoreException, you will understand why
<? super Horse> syntex has been made. This syntax is made to avoid situations that arose with Array in ArrayStoreException.

It has been made actually to restrice containers for ex: ArrayList<Animal>, ArrayList<Cat>. So that we cannot pass wrong container. Compiler will force use to pass right container.

If you declare reference List<? super Horse>, then you cannot pass the container ArrayList<Cat> that can take cat . You have to pass minimum container that could take Horse, like ArrayList<Horse>, ArrayList<Animal>, ArrayList<Object> that can atleast take Horse and its subclasses.
[ December 09, 2008: Message edited by: Punit Singh ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Generics - super
 
Similar Threads
Generics
Generics
Generics
generics
Generics