13

Please explain this generic code wildcard compile time error:

//no compile time error.
List<? extends Number> x = new ArrayList<>(); 

//compile time error.  
List<? extends Number> x = new ArrayList<? extends Number>();
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
Sam Adamsh
  • 3,331
  • 8
  • 32
  • 53
  • 2
    first example works on java 7 obviously and not on java 6 since the optional diamonds werent allowed in 6. second example fails in both – Sam Adamsh Feb 05 '12 at 05:56
  • 1
    First one definitely wouldn't work on 6; no diamond operator. As to the rest; you might want to check this resource: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html – BillRobertson42 Feb 05 '12 at 06:00

2 Answers2

27

It's invalid syntax to instantiate a generic type with wildcards. The type List<? extends Number> means a List of some type that is or extends Number. To create an instance of this type doesn't make sense, because with instantiation you're creating something specific:

new ArrayList<? extends Number>();//compiler:"Wait, what am I creating exactly?" 

Generic types with wildcards only make sense for variables and method parameters, because this allows greater freedom in what can be assigned/passed into them.

//compiler:"Okay, so passing in a List<Integer> or a List<Double> are both fine"
public void eatSomeNumbers(List<? extends Number> numbers) {
    for (Number number : numbers) {
        System.out.println("om nom " + number + " nom");
    }
}

Make sure to keep in mind the limitations that come with using wildcards.

List<? extends Number> numList = ...
numList.add(new Integer(3));//compiler:"Nope, cause that might be a List<Double>"

As for your first example, the diamond is a new feature in Java 7 that allows the compiler to infer the type of the new generic instance, based on the type of the variable it's assigned to. In this case:

List<? extends Number> x = new ArrayList<>();

The compiler is most likely inferring new ArrayList<Number>() here, but what's inferred hardly matters, as long as it's a valid assignment to the given variable. This was the reason for the diamond operator being introduced - that specifying the generic type of a new object was redundant, as long some generic type would make it a valid assignment/argument.

This reasoning only makes sense if you remember that generics in Java are a purely compile-time language feature, because of type erasure, and have no meaning at runtime. Wildcards exist only because of this limitation. By contrast, in C# generic type information sticks around at runtime - and generic wildcards don't exist in that language.

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
  • Is there any way to get around this restriction when instantiating anonymous classes? – shmosel Aug 25 '16 at 00:27
  • @shmosel I don't think so, but I'm not sure what the benefit would be of e.g. `new Foo>() { }` over `new Foo() { }`. Could you explain more about your use case? – Paul Bellora Aug 29 '16 at 15:48
1

Use

 List<? extends Number> x = new ArrayList<Number>();

instead.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347