tags:

views:

206

answers:

3

I wrote this simple test code, by adapting a piece from a book, to help me understand the working of generic methods in Java. The line that I marked is supposed to work, why isn't it?

import java.util.*;

class Test {
public static void main(String args[]){
    List<Number> input = null;
    List<Number> output=null;

    output = Test.process(input); // fail, why??

    } 
public static <E extends Number> List <? super E> process (List <E> nums){

    List <E>eList = new ArrayList<E>();
    return eList;
    }

}

edit: Well, the code works when changing List<? super E> to List<E>, that's great, but I'm still not sure if I may have missed something or if the book I took this from may have a mistake. Please read the question as it appears there:

  1. Given a method declared as:

public static < E extends Number > List < ? super E > process (List nums)

A programmer wants to use this method like this:

// INSERT DECLARATIONS HERE
    output = process(input);

Which pairs of declarations could be placed at // INSERT DECLARATIONS HERE to allow the code to compile? (Choose all that apply.)

A. ArrayList<Integer> input = null;
   ArrayList<Integer> output = null;

B. ArrayList<Integer> input = null;
   List<Integer> output = null;

C. ArrayList<Integer> input = null;
   List<Number> output = null;

D. List<Number> input = null;
   ArrayList<Integer> output = null;

E. List<Number> input = null;
   List<Number> output = null;

F. List<Integer> input = null;
   List<Integer> output = null;

G. None of the above.

Answer: B, E, and F are correct. The return type of process is definitely declared as a List, not an ArrayList, so A and D are wrong. C is wrong because the return type evaluates to List<Integer>, and that can't be assigned to a variable of type List<Number>. Of course all these would probably cause a NullPointerException since the variables are still null—but the question only asked us to get the code to compile.

None of the options mentioned on the book have worked on my code. Can I safely mark it as a mistake on Kathy Sierra's part or am I missing something here?

A: 

try:

import java.util.*;

class Test {
public static void main(String args[]){
    List<Number> input = null;
    List<Number> output=null;

    output = Test.process(input); // fail, why??

    } 
public static <E extends Number> List <E> process (List <E> nums){

    List <E>eList = new ArrayList<E>();
    return eList;
    }

}
Sam
Maybe a brief explanation to go with your code sample? :)
Marc Novakowski
Oh..why did you take away the List <? super E>?
omgzor
+6  A: 

The problem is that you are declaring the return type of your method as

List<? super E>, i.e. List<? super Number>

but assigning it to a

List<Number>

So you should either assign it to a

List<? super Number>

or declare the return type as

List<E> i.e. List<Number>

(Verbose formatting because inline code does not show generics correctly.)

If the book claims assigning the return value of the method is possible in the way you describe it then indeed it seems to be a mistake in the book. It would be correct if the method returned a List of E (as above).

Fabian Steeg
hmmm.. I'll edit the question. I think there may be a mistake on the book..
omgzor
A: 

You method returns a List. We don't know what it's a list of, but it's definitely a list of some superclass of Number. For instance: maybe it's returning a list of Object - the caller doesn't know. However, we know that whatever kind of List it returns, it's always ok to put a Number into it.

You are assigning it to a List of Number. That means that whenever you call output.get(n), you'll always get a Number back.

See the problem? The return value of process() does not honour the contract that output must abide by.

paulmurray