views:

188

answers:

2
+1  Q: 

Generics confusion

Below is a question from Kathy & Bert Bates SCJP 5 preparation CD. I have posted this elsewhere too, but have not gotten a satisfactory explanation until now.... Please help me understand this:

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?

  • 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)
  • F. public static <? extends T> List<T> backwards(List<T> input)

I understand that A and B are correct; however, not why are D and E also right. I can see that C and F are also incorrect. Can someone please tell me why D and E are correct.

+1  A: 

Because a List<T> is a List<? extends T> and a List<? super T>, by definition.
? extends T is a wildcard indicating T or a subtype, and ? super T is a wildcard indicating T or a supertype. Therefore, returning a List<T> will satisfy both return types.

There are reasons for preferring to return one or the other, but the main point here is that they are legal.

Michael Myers
+2  A: 

Answer D, public static <T> List <? extends T> backwards(List <T> input), returns a list that can contain type T or any of its subclasses. Since it can hold T, it can hold any element in the input, and is "correct" in that sense.

Answer E, public static <T> List <? super T> backwards(List <T> input), is similar, but returns a list that can hold T or any super class. Since it can also hold the input elements, it is also "correct."

Choosing one of these alternatives will impact what a user might expect to do with the resulting list.

  • With the List<? extends T> output, one can iterate over the list and assign each element to a variable of type T, but no elements, even of type T, can be safely added to the List. (Someone might be referring to this list as List<SubT>, and would get a ClassCastException when trying to retrieve the T as a SubT.)

  • With the List<? super T> output, one can safely add elements to the List if they are of type T. However, an element from the list can only be safely assigned to a variable of type Object. (Someone might be referring to this list as List<Object>, and adding instances of Object or other superclasses of T).

  • With the List<T>, one can safely assign the elements of the list to a variable of type T, and can add elements of type T to the list (assuming it's a modifiable List implementation).

erickson
What, then, is the use of the type List<? super T>, since you can only extract the elements as Objects?
Software Monkey
Items of type T can be added to a List<? super T>. The "owner" of the list might refer to it as List<SuperT>; it can iterate over the elements and access them as SuperT, while it exposes the list as a List<? super T> to other, who can add elements to the list.
erickson