0

https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html

Above states that:

List<? extends Number> a

Will work for lists of Number, Integer, Double, anything that is a subclass of number.

But in Java 8, when I try:

List<Number a

Works with Number and any subclass of it.

Is it me, or generics is overly convoluted and unclear?

Dylan Wheeler
  • 6,928
  • 14
  • 56
  • 80
hrs
  • 379
  • 4
  • 12
  • Forgot to mention that it works for mixed lists as well: Arrays.asList(1, 2, 1.1, 3.14) – hrs Jul 14 '16 at 12:08
  • 1
    I think your question got cut off a bit. It looks like generics are behaving as the documentation states. Then what is the problem? – Tim Biegeleisen Jul 14 '16 at 12:08
  • "To write the method that works on lists of Number and the subtypes of Number, such as Integer, Double, and Float, you would specify List extends Number>. The term List is more restrictive than List extends Number> because the former matches a list of type Number only, whereas the latter matches a list of type Number or any of its subclasses." It states that it works on list of type Number only. – hrs Jul 14 '16 at 12:20

2 Answers2

0

Let's say you're writing a generic method that takes in a list of Number, since Number is the minimal interface you require for the method to work.

If you write the method like this:

public void myMethod(List<Number> list) {...}

Than this works fine if users pass in a List<Number>, but they can not pass in a List<Integer> for example, because generics are invariant. This means that a List<Integer> can not be assigned to a List<Number>.


But let's say that, in your method, you're only taking things out of the list, and care only that they are any subclass of Number (i.e. the list is a producer). For your purposes it would be fine for users to pass in a List<Integer>.

This is where the bounded wildcard comes in.

By writing:

public void myMethod(List<? extends Number> list) {...}

You make it okay for users to pass in List<Integer>, since it is assignable to List<? extends Number>. But if you retrieve an element from the list, you can still be sure that it is a Number.

One important difference though, is that you can not add a Number to this list any more. Since the list might actually be a List<Integer>, adding a Number would not be type safe.

Community
  • 1
  • 1
Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
0

List<Number> does not mean it cannot contain an Integer - you can have an Integer in such list as well as a Double, even both in the same list.

What you cannot do is assign a List<Integer> into List<Number>. Here's what would happen if you were allowed to do that:

List<Integer> intList = new ArrayList<Integer>();
List<Number> numberList = intList; // suppose this was possible
Number myNum = new Double(...);
numberList.add(myNum); // it's OK to put a Number in List<Number>
Integer myInt = intList.get(0); // myInt now equals myNum, I have Integer that's in fact a Double. Oops.
Jiri Tousek
  • 12,211
  • 5
  • 29
  • 43