Generic Methods
A method can declare its own type parameter, completely independent of whether the class it belongs to is generic. This lets you write a single method that works across many types, even inside an ordinary, non-generic class.
Declaring a generic method
The type parameter is declared in angle brackets before the return type, right after the access modifier (and static, if present). That declaration introduces the type parameter, which can then be used as the return type or in the parameter list.
A generic printArray method
public class Utils {
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}
public static void main(String[] args) {
Integer[] intArray = { 1, 2, 3 };
String[] stringArray = { "a", "b", "c" };
printArray(intArray); // works
printArray(stringArray); // works — same method, different type
}
}Here <T> right after static is the method's own type parameter declaration. It has nothing to do with any type parameter the enclosing class might have — Utils above is not even generic.
A worked example: generic swap
A classic use case is a method that swaps two elements in an array, regardless of what type the array holds.
Swapping two elements in any array
public class Utils {
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void main(String[] args) {
String[] names = { "Alice", "Bob", "Charlie" };
swap(names, 0, 2);
System.out.println(Arrays.toString(names)); // [Charlie, Bob, Alice]
Integer[] scores = { 10, 20, 30 };
swap(scores, 0, 1);
System.out.println(Arrays.toString(scores)); // [20, 10, 30]
}
}Type inference at the call site
Notice that none of the calls above wrote out the type argument explicitly — there is no Utils.<String>swap(names, 0, 2) anywhere. The compiler figures out T by looking at the arguments you pass in, a process called type inference. You can spell out the type argument explicitly if you ever need to disambiguate, but in practice it is almost always omitted.
Explicit type argument (rarely needed)
// Explicit — verbose, and almost never necessary Utils.<String>swap(names, 0, 2); // Inferred — what you'd actually write Utils.swap(names, 0, 2);
A method can declare its own type parameter with
<T>placed before the return type.This works even in a non-generic class — the type parameter belongs to the method, not the class.
The type parameter can be used for parameter types and the return type within that method.
Type inference almost always lets you omit the explicit type argument at the call site.