Two Laptop Bag*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes Master Exam / Generics Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "Master Exam / Generics" Watch "Master Exam / Generics" New topic
Author

Master Exam / Generics

John Stark
Ranch Hand

Joined: Jul 19, 2011
Posts: 185
Hi,

There is a question asking what fragments can be inserted into the following code:

One correct answer is:


I tried it out and it compiles. But when I call the method with some List as parameter what is the actual type of T? For example when I do


Then T is of type Number? What is the effect of the question mark in (List<? extends T> input)?

Thanks,

John
Joseph Arnold
Ranch Hand

Joined: Oct 05, 2010
Posts: 42
In this case, T is of type number. The function can take any parameter that is of type T or is a sub class of T.
Helen Ma
Ranch Hand

Joined: Nov 01, 2011
Posts: 451
1. public static<T> List<T> backwards(List<? extends T> input){...}
says backwards method takes a list of type T and returns a list of type T. The compiler does not know what T is , so it can only take T as argument.

2. How about this?
public static<T> List < ? extends T> backwards( List<? extends T> input) { .. .}
says backwards takes a list of type T and returns a list of type T or some subtypes of it.
Let's say if you have Animal class and it has a Bird subtype and you do this:

List<Animal> input = new ArrayList<Animal>();

2.1 List <? extends Animal> output = backwards(input); //compiles , the compiler says "Hey programmer, backwards returns a ArrayList<Animal> , List<? extends Animal> = new ArrayList<Animal>();

2.2 List<? extends Object> output = backwards(input) ; //compiles, the compiler says "Hey, backwards returns a ArrayList<Animal> , List<? extends Object> = new ArrayList<Animal>();

2.3 List<Object> output = backwards (input) ; //won't compile the compiler says "Hey, List<Object> a = new ArrayList<Animal> won't work.

2.4 List <? super Animal> output = backwards (input) //won't compile , the compiler says "Hey, what happens if backward returns new ArrayList<Bird>?

2.5 List<Animal> output = backwards(input) //won't compile, the compiler says "Hey, what happens if List<Animal> a = new ArrayList<Bird> ?

Correct me if I am wrong.
Helen Ma
Ranch Hand

Joined: Nov 01, 2011
Posts: 451
One more point I want to make, correct me if I am wrong.

static <T> List<T> backwards (List<? extends T> input){...}

When the compiler sees this method declaration, the compile will say " I can only take Type T object, I don't know what T is until the program is run. I can only take List<T>. If you give me List<Animal>, I will take it as the argument. If you give me List<Bird>, I will take it as the argument. "

Therefore, backwards will return List<Animal> if you pass in List<Animal> and etc.....

List<Bird> input = new ArrayList<Bird>();
When you use backward methods like this in your main method, List<? super Animal> a = backwards(input) ; the compile will say "Hey, you give me List<Bird>, I output a List<Bird>. But you assign me List <? super Animal> , I won't compile it!"

Helen Ma
Ranch Hand

Joined: Nov 01, 2011
Posts: 451
One more thing:
if you have this:
public static <T> List< ? extends T > backward(List<? extends T> input){ ...}

The compiler says " Hey, you pass in a List<T> and I return you a List of T or T subtypes.

In the main method , you wrote this:
List<Animal> input1= new ArrayList<Animal>();
input1.add(new Bird());
List <Bird> output = (List<Bird>) backward(input1);
1. You notice a warning in ( List<Bird> )backward(input1);
2. The compiler warns you "Hey, you pass in a list of animal, I don't know you add a bird object to it until you run the program. I can return a list of animal or its subtype, bird to you as I promise.
It is up to you to take the risk to type cast it a list of bird.

In the main method , you wrote this:
List<Animal> input1= new ArrayList<Animal>();
input1.add(new Bird());
List <Basket> output = (List<Basket>) backward(input1);
1. You notice a compilation error on the last line.
2. The compiler yells at you " Hey, I can only return a list of animal or a list of animal subtypes, bird. You type cast it into a list of Basket, which is not a subtype of Animal!"

John Stark
Ranch Hand

Joined: Jul 19, 2011
Posts: 185
Hi Helen,

Thanks for the nice examples, they are pretty clear.
What is the meaning of the '?' for the method parameter type?

What is the fifference between

and

?
John
Anayonkar Shivalkar
Bartender

Joined: Dec 08, 2010
Posts: 1502
    
    5

Hi John,

Below is the difference:


This means that 'input' must be list of type T.


This means that 'input' can be list of anything 'assignable' to type T (i.e. anything which is-a T).

To make is more clear:
Now, in first definition, since output is a list of type T and input is also list of type T,

is valid code.

But, in second definition, input is not a list of type T, but it is list of sub-type of T. Hence

is not a valid code (it gives compile time error).

There are, however, two important things to remember:
1) List<? extends T> does not have is-a relationship with List<T>. Yes, all subtypes of T can be added to List<T>, but not to List<? extends T>. e.g. List<Animals> can contain Dog, Cat etc. but List<Dog> can contain only Dog, not Cat.
2) For above mentioned reason, when we pass List<? extends T> as argument, we cannot add anything to that list (that would be compile time error). e.g. if we pass List<? extends Animal>, compiler will not know if it is List<Cat>, List<Dog> or something else. Further, it won't even know if programmer is adding new Cat() to a List<Dog>. So, it doesn't allow to add anything altogether.

I hope this helps.


Regards,
Anayonkar Shivalkar (SCJP, SCWCD, OCMJD, OCEEJBD)
John Stark
Ranch Hand

Joined: Jul 19, 2011
Posts: 185
Now, in first definition, since output is a list of type T and input is also list of type T,

is valid code.

But, in second definition, input is not a list of type T, but it is list of sub-type of T. Hence

is not a valid code (it gives compile time error).

Doh, that is indeed true. Thanks for that Anayonkar.

John
Helen Ma
Ranch Hand

Joined: Nov 01, 2011
Posts: 451
Some more examples about <? extends E> as parameters :
Case 1 Generic parameter with class definition :
ArrayList class has a generic parameter <E> . It has addAll(Collection<? extends E> c) {....} method.
The compiler says about this class : Hey programmers, instantiate an ArrayList object with any type E, you can pass in a Collection with any type E or below it to addAll method and I will add the collection to the array list.

When programmer writes this Collection< ? extends Bird> c = new ArrayList<Bird>() ; ArrayList<Animal> alist = new ArrayList<Animal> ; a.addAll(c);

The programmer says: Hey compiler, I have a collection of object of Bird type or its subtype, please add the collection to alist.
Compiler says: c is a collection of Bird type , which is a subtype of Animal, so I am happy.

Case 2 Generic parameter with generic method:
Some classes may not have generic parameter, but it has generic methods.
static <T> List<T> backwards (List< ? extends T> a , List<T>b) { ..... }
The compiler says : Hey programmer, I accepts any type T, pass me a list of T and a list of T or its subtype, I will return you a list of T.
case 2.1
Programmer : List < Animal> b1 = new ArrayList<Animal>(); List<?extends Animal> a1 = new ArrayList<Bird>();

List<Animal> result = backwards(a1, b1);
Compiler verifies : I takes T, b1 is an animal list, so I substitute T with Animal . a is T or subtype, a1 is ok. I return List<Animal> as T is replaced by Animal, so List<Animal> result = .... compiles.....

What about this ?
case 2.2
Programmer says :
List < ? super Animal> b1 = new ArrayList<Animal>();
List<? extends Animal> a1 = new ArrayList<Bird>();

List<Animal> result = backwards(a1, b1); //wont' compile.
Compiler yells : Hey, b1 is a list with Animal or its parents or Object class, I don't know what exactly b1 has . What happens if b1 is a list of Object ? Can List<Animal> result = new ArrayList<Object> ? No. Never assign different object type for generic. Correction : List<? super Animal> result = .... Because the return type is List<T> and b is List<T> . T is <? super Animal>.


case 2.3
Programmer says List<? extends Animal> b1 = new ArrayList<Animal>();
List<? extends Animal> a1 = new ArrayList<Bird>();
backwards(a1, b1) //won't compile
Compiler yells: Hey, b1 may be a list of Dog, Cat, Bird, while its counterpart a1 must be a list of Dog (or its subtype...) according.
List<? extends Animal> result = backwards(a1, b1) //won't compile
List<Animal> result = backwards(a1,b1) //won't compile.
The problem is in backwards.
Reason:
1. When b1 is list of Dog, a1 must be a list of Dog or subtypes.
2. When b1 is a list of Bird, a1 must be a list of Bird or subtypes.
3. But here b1 can be a list of Dog, a1 can be a list of Cat. I won't compile.


case 2.4 static <T> List<T> backwards (List< ? extends T> a ) { ..... }
Compiler advices : unlike case 2.3, my argument a does not have a counterpart.
In case 2.3, treat a and b as husband and wife. If the wife, b takes a Dog object, the husband takes a Dog or its subtype Object. If the wife takes a Cat, the husband takes a Cat (or subtype).
In case 2.4, treat a as a single man that is not controlled by his wife. Since <? extends T> means a type of T or T-subtype, a can take anything and the compile will promise you to return a list of that type.
Unlike case 1, Collection < ? extends E> is bound by E or subtype declared by ArrayList class, the T is not bound by anything at all. So, in this case, List<? extends T> is the same as List<T>

Therefore, List<? extends Animal> input1= new ArrayList<Animal>();
List<? super Animal > result = backwards( input1); //compiles, because List<? extends Animal> input1 is treated as List<Animal> input1
List<? extends Animal > result = backwards( input1); //compiles
List<Animal> result = backwards(input1); //compiles

correct me if I am wrong in those examples.
I think in the exam, if you are given a method with return type List<T> and T is generic, never choose those choices with a concrete type on the left hand side likes List<Object> o = method(); or List<Animal> a = method() ...



Helen Ma
Ranch Hand

Joined: Nov 01, 2011
Posts: 451
In conclusion, in the exam if you are given a return type and input parameters that involves generic parameters, here are two things you may consider:
1. What return type your method will be depending on the input parameter type?
2. What type you can assign the return type from your method.

For example, you are given <T> List<? extends T> methodA( List<T>) {.... }. Make sure you input List<T> and will return List of T or T-subtype depending how the code provided inside the method.
For another example, you are given <T> List<? super T> methodA (List <? super T>). Whatever List element type T you pass in, it will return List<? super T>.


How about assigning a variable to the method output? In order to do that, the partial type hierarchy is considered. It is just like inheritance. eg Object() o = new Animal();
Here are some examples:
Object a = new List();
List<?> a1 = null; List a2 = al; // List is a parent of List<?>
List< ? extends Number> a3 = null; a2 = a3; // List is a parent of List <? extends Number> and so on...
List <? extends Integer> a4 = null ; a3 = a4;
List<? super Integer> a5 = null ;
List <? super Number> a6 = null ; a5 = a6 // List <? super Integer> is a parent of List<? super Number> and so on....
a1 = a5 // List<?> is a parent of List <? super Integer>


Therefore , if your methodA returns List< ? super Animal> , you can write this: List<? super Animal> a = methodA(...) ; or List< ?> a = methodA(...); or List a = methodA(...);



Google A Programmer's Guide to Java SCJP Certification A complete primer 3 rd editon by Mughal and Rasmussen. You may be able to open the pdf book. Read P 678 Figure 14.5
You will see the Partial Type Hierarchy
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Master Exam / Generics
 
Similar Threads
How to interpret Generics using wildcard and type parameters
Generics
Solution needed for Generics Question
Question about Generics and <? extends T>
K & B Mock exam Generics doubt