There may be times when you want to restrict the types that can be used as type parameters.
For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. The Number class is the superclass of classes BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, and Short.
To declare a bounded type parameter, list the type parameter's name, followed by extends, followed by its upper bound.
<T extends Number> Number maximum(T number1, T number2, T number3){
// ...
}Here, extends is used in a general sense to mean either
extends as in classes orimplements as in interfaces.This method:
public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
T max = x; // assume x is initially the largest
if (y.compareTo(max) > 0)
max = y; // y is the largest so far
if (z.compareTo(max) > 0)
max = z; // z is the largest
return max; // returns the largest object
}becomes:
public static Comparable maximum(Comparable x, Comparable y, Comparable z) {
Comparable max = x;
if (y.compareTo(max) > 0)
max = y;
if (z.compareTo(max) > 0)
max = z;
return max;
}public static void main(String[] args) {
List<Integer> integers = Arrays.asList(10, 20, 30, 40);
System.out.println("Max integer: " + getMax(integers));
List<Long> longs = Arrays.asList(10L, 20L);
System.out.println("Max long: " + getMax(longs));
List<Double> doubles = Arrays.asList(10.1, 10.2, 10.3, 10.4);
System.out.println("Max double: " + getMax(doubles));
}You can find the solution to this exercise here.
In generic code, the question mark ?, called wildcard, represents an unknown type.
The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>.
There are two scenarios where an unbounded wildcard is a useful approach.
Object class.List.size or List.clear.Here is an example of a method that can be implemented using Object::toString().
public static void printList(List<Object> list) {
for (Object elem : list)
System.out.println(elem + " ");
System.out.println();
}The goal of printList is to print a list of any type, but it fails to achieve that goal. It prints only a list of objects, i.e., List<Object>. It cannot print List<Integer>, List<String>, List<Double>, because they are not subtypes of List<Object>.
Instead, if we use a wildcard, it can handle all of these cases.
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}Example from this StackOverflow answer.
You can use an upper bounded wildcard to relax the restrictions on a variable.
For example, say you want to write a method that works on
List<Integer>,List<Double>, andList<Number>.You can achieve this by using an upper bounded wildcard.
List<? extends Number>But what is the difference between the following expressions?
List<? extends Number>List<T extends Number>You declare a T so that you can refer to it again.
Here is an example in which it is useful to use upper-bounded wildcards.
List<Person> merge( List<? extends Person> list1, List<? extends Person> list2) {
List<Person> merged = new ArrayList<>();
merged.addAll(list1);
merged.addAll(list2);
return merged;
}Which can later be used as:
List<Person> people = merge(new ArrayList<Person>(), new ArrayList<Student>() );or as:
List<Person> people = merge(new ArrayList<Student>(), new ArrayList<Teacher>() );None of the above would have worked if the collect method had been declared as:
List<Person> merge(List<Person> list1, List<Person> list2)Example from this StackOverflow answer.
Say you want to write a method that puts Integer objects into a list. To maximize flexibility, you would like the method to work on anything that can hold Integer values, that is:
List<Integer>,List<Number>, andList<Object>.To write the method that works on lists of Integer and the supertypes of Integer, such as Integer, Number, and Object, you would specify:
List<? super Integer>. <T> vs. <?> (1)Sometimes, wildcards and type parameters do the same thing, but for certain purposes, you will need type parameters to:
Suppose you want to ensure that the src and dest lists passed to copy() have the same type.
You can do it with type parameters.
public static <T extends Number> void copy(List<T> dest, List<T> src)Making it safe to copy elements from src to dest.
If you were to use a wildcard instead:
public static void copy(List<? extends Number> dest, List<? extends Number> src)You would be able to pass List<Integer> and List<Float> as dest and src, making it unsafe to move elements from src to dest.
<T> vs. <?> (2)Another big difference is that <T> allows you to refer to "T" within the method as if the concrete class was given.
public <T extends Animal> void takeThing(ArrayList<T> list){
T first = list.get(0);
// ...
}If you had used a wildcard instead, you would not be able to do that.
public void takeThing(ArrayList<? extends Animal> list){
// ...
}