Java 泛型方法
泛型方法是在方法層級定義型別參數,讓單一方法可以處理不同型別的參數。
基本語法
型別參數放在回傳型別之前:
public class Utility {
// 泛型方法
public static <T> void print(T item) {
System.out.println(item);
}
public static <T> T getFirst(T[] array) {
if (array == null || array.length == 0) {
return null;
}
return array[0];
}
}
// 使用
Utility.print("Hello"); // 自動推斷為 String
Utility.print(123); // 自動推斷為 Integer
String first = Utility.getFirst(new String[]{"a", "b", "c"}); // "a"
Integer num = Utility.getFirst(new Integer[]{1, 2, 3}); // 1
型別推斷
Java 通常可以自動推斷型別參數:
// 自動推斷
List<String> list1 = Arrays.asList("a", "b", "c");
// 明確指定(偶爾需要)
List<String> list2 = Arrays.<String>asList("a", "b", "c");
// 需要明確指定的情況
Collections.<String>emptyList();
多個型別參數
public static <K, V> Map<K, V> createMap(K key, V value) {
Map<K, V> map = new HashMap<>();
map.put(key, value);
return map;
}
// 使用
Map<String, Integer> map = createMap("age", 25);
有界型別參數
// T 必須實作 Comparable
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
// 使用
int maxInt = max(10, 20); // 20
String maxStr = max("a", "z"); // "z"
// 多重上界
public static <T extends Number & Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
泛型方法 vs 泛型類別
// 泛型類別:型別在類別層級定義
public class Box<T> {
private T content;
public void set(T content) {
this.content = content;
}
public T get() {
return content;
}
}
// 泛型方法:型別在方法層級定義
public class Utility {
public static <T> T getFirst(List<T> list) {
return list.isEmpty() ? null : list.get(0);
}
}
組合使用
public class Container<T> {
private List<T> items = new ArrayList<>();
public void add(T item) {
items.add(item);
}
// 類別的型別參數
public T getFirst() {
return items.isEmpty() ? null : items.get(0);
}
// 方法自己的型別參數
public <U> U transform(Function<T, U> transformer) {
if (items.isEmpty()) return null;
return transformer.apply(items.get(0));
}
}
// 使用
Container<String> container = new Container<>();
container.add("hello");
Integer length = container.transform(String::length); // 5
靜態泛型方法
public class Collections {
// 靜態泛型方法
public static <T> List<T> singletonList(T item) {
List<T> list = new ArrayList<>();
list.add(item);
return list;
}
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static <T extends Comparable<T>> void sort(List<T> list) {
// 排序邏輯
}
}
實例泛型方法
public class Converter {
public <T, R> R convert(T input, Function<T, R> converter) {
return converter.apply(input);
}
public <T> Optional<T> nullSafe(T value) {
return Optional.ofNullable(value);
}
}
// 使用
Converter converter = new Converter();
Integer length = converter.convert("hello", String::length);
Optional<String> opt = converter.nullSafe(null);
實際範例
交換陣列元素
public static <T> void swap(T[] array, int i, int j) {
if (i < 0 || i >= array.length || j < 0 || j >= array.length) {
throw new IndexOutOfBoundsException();
}
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// 使用
String[] strings = {"a", "b", "c"};
swap(strings, 0, 2); // ["c", "b", "a"]
Integer[] numbers = {1, 2, 3};
swap(numbers, 0, 1); // [2, 1, 3]
找出最大值
public static <T extends Comparable<T>> T findMax(List<T> list) {
if (list.isEmpty()) {
throw new IllegalArgumentException("List is empty");
}
T max = list.get(0);
for (int i = 1; i < list.size(); i++) {
if (list.get(i).compareTo(max) > 0) {
max = list.get(i);
}
}
return max;
}
// 使用
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);
Integer max = findMax(numbers); // 9
List<String> words = Arrays.asList("apple", "banana", "cherry");
String maxWord = findMax(words); // "cherry"
安全轉型
public static <T> Optional<T> safeCast(Object obj, Class<T> clazz) {
if (clazz.isInstance(obj)) {
return Optional.of(clazz.cast(obj));
}
return Optional.empty();
}
// 使用
Object value = "Hello";
Optional<String> str = safeCast(value, String.class); // Optional["Hello"]
Optional<Integer> num = safeCast(value, Integer.class); // Optional.empty
複製集合
public static <T> List<T> copy(Collection<? extends T> source) {
return new ArrayList<>(source);
}
public static <T> void copyTo(Collection<? extends T> source,
Collection<? super T> target) {
target.addAll(source);
}
// 使用
List<Integer> original = Arrays.asList(1, 2, 3);
List<Integer> copied = copy(original);
List<Number> numbers = new ArrayList<>();
copyTo(original, numbers); // Integer 是 Number 的子類別
建立物件
public static <T> T createInstance(Class<T> clazz)
throws ReflectiveOperationException {
return clazz.getDeclaredConstructor().newInstance();
}
// 使用
String str = createInstance(String.class);
ArrayList list = createInstance(ArrayList.class);
過濾集合
public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
List<T> result = new ArrayList<>();
for (T item : list) {
if (predicate.test(item)) {
result.add(item);
}
}
return result;
}
// 使用
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evens = filter(numbers, n -> n % 2 == 0); // [2, 4, 6]
List<String> words = Arrays.asList("a", "bb", "ccc", "dddd");
List<String> longWords = filter(words, s -> s.length() > 2); // ["ccc", "dddd"]
映射集合
public static <T, R> List<R> map(List<T> list, Function<T, R> mapper) {
List<R> result = new ArrayList<>();
for (T item : list) {
result.add(mapper.apply(item));
}
return result;
}
// 使用
List<String> words = Arrays.asList("a", "bb", "ccc");
List<Integer> lengths = map(words, String::length); // [1, 2, 3]
List<String> upper = map(words, String::toUpperCase); // ["A", "BB", "CCC"]
常見錯誤
型別擦除問題
// ✗ 編譯錯誤:型別擦除後方法簽名相同
public void process(List<String> list) { }
public void process(List<Integer> list) { } // 衝突!
// ✓ 解決方式:改用不同的方法名稱
public void processStrings(List<String> list) { }
public void processIntegers(List<Integer> list) { }
無法建立泛型陣列
// ✗ 無法建立泛型陣列
public static <T> T[] toArray(List<T> list) {
return new T[list.size()]; // 編譯錯誤
}
// ✓ 使用 Array.newInstance
@SuppressWarnings("unchecked")
public static <T> T[] toArray(List<T> list, Class<T> clazz) {
T[] array = (T[]) Array.newInstance(clazz, list.size());
return list.toArray(array);
}
重點整理
- 泛型方法在回傳型別前宣告型別參數:
<T> - Java 通常可以自動推斷型別
- 使用
extends限制型別上界 - 泛型方法可以是靜態或實例方法
- 方法的型別參數與類別的型別參數獨立
- 注意型別擦除帶來的限制