2

I'm studying for the SCJP/OCPJP and I came across a sample question that seams strange to me.

The sample code instantiated two generic collections:

List<?> list = new ArrayList<?>();
List<? extends Object> list2 = new ArrayList<? extends Object>();

The "correct" answer to the question was that this code would compile but adding to either collection would produce a runtime error.

When I try to compile code like this I just get errors. The Java tutorial does not even show this type of code, it instead usually uses wildcards as a part of an upcast.

Collection<?> c = new ArrayList<String>();

Are the two generic collections above even legitimate code? The second by my logic would only disallow interfaces. The first one looks completely useless. Why use a generic that makes no attempt at control?

Roman C
  • 49,761
  • 33
  • 66
  • 176
jeremyjjbrown
  • 7,772
  • 5
  • 43
  • 55
  • Don't see how this would compile AND you can add to both collections just fine - just only exactly ONE object. I leave it as an exercise for the reader to figure out which object is valid for every class :) – Voo Dec 30 '11 at 19:26
  • You can't do either. I wanted to find out if the sample question/answer was wrong and apparently it is. – jeremyjjbrown Dec 30 '11 at 20:18
  • Down voted just now for what reason? – jeremyjjbrown Mar 01 '14 at 18:52

4 Answers4

4

Check out the excellent Java generics tutorial PDF. More specifically the section about wildcards contains the answer to your question, and I quote

Collection<?> c = new ArrayList<String>();
c.add( new Object() );

Since we don’t know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don’t know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.

Robin
  • 36,233
  • 5
  • 47
  • 99
2

If you want to declare Type at runtime, you can do something like this:

public class Clazz1<T> {

private final List<T> list = new ArrayList<T>();

private List<T> getList() {
    return list;
}

/**
 * @param args
 */
public static void main(String[] args) {
    Clazz1<Integer> clazzInt = new Clazz1<Integer>();
    clazzInt.getList().add(2);
    System.out.println(clazzInt.getList());

    Clazz1<String> clazzString = new Clazz1<String>();
    clazzString.getList().add("test");
    System.out.println(clazzString.getList());
}

}
1

I answered this somewhat before in this answer. ? cannot be used in the instantiation. I'm not sure why it says the code would compile, none of the java compilers I have used would allow that. You could do what is shown above by the following:

List<?> list = new ArrayList();

That would compile and run, but you couldn't do:

list.add("hello world"); //This wouldn't compile
Community
  • 1
  • 1
Daniel Moses
  • 5,872
  • 26
  • 39
0

new produces a concrete instance of an object. The concrete instance can have only one type, including any generics. Knowing this, wildcards cannot work with new.

barfuin
  • 16,865
  • 10
  • 85
  • 132