Very well answered by Tagir and I would like to add few more points.
First of all the following will not even compile:
List<? extends Number> list = new List<Integer>();
I hope you know List
is an interface. So now we have:
List<? extends Number> list = new ArrayList<Integer>();
Here list
is a reference of type List<? extends Number>
and it simply means it can refer to a list in which every element IS Number
or more specifically every element extends class Number
so it means all the following are permissible:
list = new ArrayList<Float>();
list = new ArrayList<Long>();
But we can not instantiate as a list of Object
as Object
is not Number
.
list = new ArrayList<Object>(); // compile time error
Now when we take element out of this list we know only one thing for sure that it is going to be a Number
and it means not sure but it can be Integer
or Long
as well. So we need casting as:
Integer integer = (Integer) list.get(0);
Float floatValue = (Float) list.get(0);
Number number = list.get(0); // no casting if assigning it to Number
This is mainly useful when we are producing the elements and not consuming them (check PECS). For example useful in printing the elements but not useful when you want to add any element in it as it will not even compile.
private static void printMe(List<? extends Number> numbers) {
for(Number number : numbers) {
System.out.println(number);
}
}
This can be invoked then as:
List<Integer> integerList = new ArrayList<>();
integerList.add(10);integerList.add(20);integerList.add(30);
printMe(integerList);
List<Long> longList = new ArrayList<>();
longList.add((long) 4.5);longList.add((long) 6.5);longList.add((long) 7.5);
printMe(longList);
This will simply print the elements in each list.