Win a copy of Functional Reactive Programming this week in the Other Languages forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

How to interpret Generics using wildcard and type parameters

 
Abhi Bhutani
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi I have read generics quiet a few times but i still get completely bowled over when i see a question that uses wildcards, type parameter all together. I am unable to interpret the code properly. So please see the question and the answer below (this is from KB book for SCJP 5), and try to explain me.


import java.util.*;
public class BackLister{
//INSERT CODE HERE
{
List<T> output = new LinkedList<T>();
for(T t: input)
output.add(0, t);
return output;
}
}

Which of the following can be inserted at //INSERT CODE HERE to compile and run without error ?

A. public static<T> List<T> backwards(List<T> input)
B. public static<T> List<T> backwards(List<? extends T> input)
C. public static<T> List<T> backwards(List<? super T> input)
D. public static<T> List<? extends T> backwards(List<T> input)
E. public static<T> List<? super T> backwards(List<T> input)

The correct answers are A, B, D, E. Only C is incorrect

For explanation purposes if you wish you could use the classes mentioned below:

class A.
Class B extends A.
class C extends B.
 
Campbell Ritchie
Sheriff
Pie
Posts: 50277
80
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I presume you have found the Java Tutorials about generics and Angelika Langer's generics FAQ? What does it say in the K&B book about that question?

Please show us what you think so far; we believe you will learn better than if we simply tell you the answer. It is actually not a particularly difficult question.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think it would help you understand if you substitute a class name for the generics and try to understand the consequences. So for example,

Class Dog
Class Terrier extends Dog
Class MiniTerrier extends Terrier

Then, for each answer replace the Generics with the appropriate class name.
For T => Terrier:
A. public static<Terrier> List<Terrier> backwards(List<Terrier> input)
B. public static<Terrier> List<Terrier> backwards(List<MiniTerrier> input)
etc...

It may come out as more obvious why C is wrong and the others are not.
 
Abhi Bhutani
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have read Java tutorial on Generics. However i am going to check out Angelika FAQ's. In the meantime this is what i understood about this question so far.

According to the book it says the best way to understand the use of type parameters is to mentally replace every occurence of the parameter type in the code with the type with which you are going to invoke the method. On that basis:

List<A> a = new ArrayList<A>();
List<B> b = new ArrayList<B>();
List<C> c = new ArrayList<C>();

1. public static<T> List<T> backwards(List<T> input)
backwards(a) or backwards(b) or backwards(c) are all correct invocations as in this case in the bytecode T is simply replaced by the class name i.e A, B or C. So this is fine.

2. public static<T> List<T> backwards(List<? extends T> input)
In this case i feel "? extends" is redundant because if i invoke method like backwards(a), then in the bytecode T is replaced by class A, then what is the use of "? extends" part.

3. public static<T> List<T> backwards(List<? super T> input)
Similarly to point 2, i feel the use of "? super" is redundant.

4. public static<T> List<? extends T> backwards(List<T> input)
Now if i invoke backwards(b), then in bytecode, T is replaced by class B, then how am i ever going to return a List or ArrayList of subtype of class B.

5. public static<T> List<? super T> backwards(List<T> input)
Same as 4, if i invoke backwards(b) how am i ever going to return a List of supertype of class B
 
Campbell Ritchie
Sheriff
Pie
Posts: 50277
80
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Abhi Bhutani:
5. public static<T> List<? super T> backwards(List<T> input)
Same as 4, if i invoke backwards(b) how am i ever going to return a List of supertype of class B
For this purpose, regard ? super B as including B, so call B a "supertype" of itself.
 
Abhi Bhutani
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Steve,

Ignore option A for the moment. Just think of option B.
If I invoked backwards(List<MiniTerrier>) then result will be:

B. public static<MiniTerrier> List<MiniTerrier> backwards(List<? extends MiniTerrier> input)

in other words now T will be replaced by MiniTerrier? isn't it ?

[edit]Disable smilies. CR[/edit]
[ September 28, 2008: Message edited by: Campbell Ritchie ]
 
Campbell Ritchie
Sheriff
Pie
Posts: 50277
80
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You say something in redundant in no 2, then you say something is redundant in no 3. Are you quite sure you know what redundant means? It implies more than is required, but does not imply incorrectness; you have already seen that no 2 was called "correct" and no 3 was called "incorrect," so "redundant" is probably not the right word to use for one of them.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Abhi Bhutani:
Hi Steve,

Ignore option A for the moment. Just think of option B.
If I invoked backwards(List<MiniTerrier>) then result will be:

B. public static<MiniTerrier> List<MiniTerrier> backwards(List<? extends MiniTerrier> input)

in other words now T will be replaced by MiniTerrier? isn't it ?

[edit]Disable smilies. CR[/edit]

[ September 28, 2008: Message edited by: Campbell Ritchie ]


Yes, in that specific case, we are trying to understand the generic case, so lets keep with Terrier since we know something about its children...

Let's expand our class family a bit.

Class Dog
Class Shepherd extends Dog
Class GermanShepherd extends Shepherd
Class AnatolianShepherd extends Shepherd
Class Terrier extends Dog
Class MiniTerrier extends Terrier
Class Yorkie extends Terrier

When you have a List<? extends Terrier> what objects can you put in the List?
When you have a List<Terrier> what objects can you put in the List?
When you have a List<? super Terrier> what objects can you put in the List?

Then:
When you have a List<? extends Terrier> what kind of Lists can you pass to the method?
When you have a List<Terrier> what kind of Lists can you pass to the method?
When you have a List<? super Terrier> what kind of Lists can you pass to the method?

Finally for each of the above, what types of Objects can you safely pull out of the List, so that you can modify it or put it in another list? (safely means without having to cast or use instanceof)
 
Abhi Bhutani
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Steve Luke:


Yes, in that specific case, we are trying to understand the generic case, so lets keep with Terrier since we know something about its children...

Let's expand our class family a bit.

Class Dog
Class Shepherd extends Dog
Class GermanShepherd extends Shepherd
Class AnatolianShepherd extends Shepherd
Class Terrier extends Dog
Class MiniTerrier extends Terrier
Class Yorkie extends Terrier

When you have a List<? extends Terrier> what objects can you put in the List?
When you have a List<Terrier> what objects can you put in the List?
When you have a List<? super Terrier> what objects can you put in the List?

Then:
When you have a List<? extends Terrier> what kind of Lists can you pass to the method?
When you have a List<Terrier> what kind of Lists can you pass to the method?
When you have a List<? super Terrier> what kind of Lists can you pass to the method?

Finally for each of the above, what types of Objects can you safely pull out of the List, so that you can modify it or put it in another list? (safely means without having to cast or use instanceof)


Answers to your questions:
1.When you have a List<? extends Terrier> what objects can you put in the List?

You can put Terrier, MniTerrier and Yorkie

2. When you have a List<Terrier> what objects can you put in the List?

Same as 1.

3. When you have a List<? super Terrier> what objects can you put in the List?

Terrier or a Dog

4. When you have a List<? extends Terrier> what kind of Lists can you pass to the method?

I can pass List<Terrier> or any of the List<subtypes of Terrier>

5. When you have a List<Terrier> what kind of Lists can you pass to the method?

I can only pass List<Terrier>

6. When you have a List<? super Terrier> what kind of Lists can you pass to the method?

I can pass List<Terrier> or List<Dog>
 
Abhi Bhutani
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I am still very confused and trying to see if i can make sense of this after Angelika's Generics website.
 
Steven Rodeo
Ranch Hand
Posts: 72
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Try this. hopefully this will clear up your head.




-------------------------------------------------------------------------
-------------------------------------------------------------------------
-------------------------------------------------------------------------



-D

[edit]Add code tags. CR[/edit]
[ November 07, 2008: Message edited by: Campbell Ritchie ]
 
Campbell Ritchie
Sheriff
Pie
Posts: 50277
80
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Please always use the code button; code is difficult to read without it. And I am afraid it probably is too late for your post to be helpful. Please look at this FAQ.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic