Methods can also have generic type parameters.
public class Example {
// The type parameter T is scoped to the method
// and is independent of type parameters of other methods.
public <T> List<T> makeList(T t1, T t2) {
List<T> result = new ArrayList<T>();
result.add(t1);
result.add(t2);
return result;
}
public void usage() {
List<String> listString = makeList("Jeff", "Atwood");
List<Integer> listInteger = makeList(1, 2);
}
}
Notice that we don't have to pass an actual type argument to a generic method. The compiler infers the type argument for us, based on the target type (e.g. the variable we assign the result to), or on the types of the actual arguments. It will generally infer the most specific type argument that will make the call type-correct.
Sometimes, albeit rarely, it can be necessary to override this type inference with explicit type arguments:
void usage() {
consumeObjects(this.<Object>makeList("Jeff", "Atwood").stream());
}
void consumeObjects(Stream<Object> stream) { ... }
It's necessary in this example because the compiler can't "look ahead" to see that Object
is desired for T
after calling stream()
and it would otherwise infer String
based on the makeList
arguments. Note that the Java language doesn't support omitting the class or object on which the method is called (this
in the above example) when type arguments are explicitly provided.