I generally prefer not to use wildcards. These are the options:
Using a List is for a list with an unknown type:
List<?> list = Arrays.asList(1, 2d, "3"); // can contain any Object
for (Object obj : list) { // you can retrieve them
System.out.println("--> " + obj);
}
list.add("a"); // compile error
Using <? extends Number>
lets you retrieve numbers from a list, but you still can't add anything:
List<? extends Number> list2 = Arrays.asList(1, 2, 3); // can contain any number
for (Number n : list2) {
System.out.println("--> " + n);
}
list2.add(5); // compile error
List<? extends Number> list3 = Arrays.asList(1, 2d, 3F); // can contain any number
for (Number n : list3) {
System.out.println("--> " + n);
}
list3.add(5); // compile error
The opposite of <? extends ...>
is <? super ...>
. This looks weird. The point is that callers of such List<>
can add stuff of the appropriate type. Retrieving is a problem though:
List<? super Integer> list4 = new ArrayList<>();
list4.add(1);
for (Integer num : list4) { } // compile error
for (Object num : list4) { } // this is fine, but not that useful
If you want a flexible data structure, you can use the right supertype. Say for instance, a List<Number>
is quite flexible. If you really need to, you can use bound types like List<T extends Number>
. You can read more about that at this answer.