Skip to content

泛型

泛型概述

泛型是JDK 5引入的特性,用于在编译时检查类型安全。

为什么使用泛型

java
// 没有泛型(Java 5之前)
List list = new ArrayList();
list.add("Hello");
list.add(100);  // 编译通过,运行时可能出错

String s = (String) list.get(0);  // 需要强制转换
String s2 = (String) list.get(1); // ClassCastException

// 使用泛型
List<String> list2 = new ArrayList<>();
list2.add("Hello");
// list2.add(100);  // 编译错误,类型安全
String s3 = list2.get(0);  // 无需转换

泛型类

定义泛型类

java
public class Box<T> {
    private T value;
    
    public void set(T value) {
        this.value = value;
    }
    
    public T get() {
        return value;
    }
}

// 使用
Box<String> stringBox = new Box<>();
stringBox.set("Hello");
System.out.println(stringBox.get());

Box<Integer> intBox = new Box<>();
intBox.set(100);
System.out.println(intBox.get());

多个类型参数

java
public class Pair<K, V> {
    private K key;
    private V value;
    
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    
    public K getKey() { return key; }
    public V getValue() { return value; }
}

// 使用
Pair<String, Integer> pair = new Pair<>("年龄", 25);
System.out.println(pair.getKey() + ": " + pair.getValue());

泛型接口

定义泛型接口

java
public interface Generator<T> {
    T generate();
}

// 实现类指定具体类型
public class StringGenerator implements Generator<String> {
    @Override
    public String generate() {
        return "Hello";
    }
}

// 实现类保留泛型
public class GenericGenerator<T> implements Generator<T> {
    @Override
    public T generate() {
        return null;
    }
}

泛型方法

定义泛型方法

java
public class GenericMethod {
    // 泛型方法
    public <T> void print(T value) {
        System.out.println(value);
    }
    
    // 泛型方法带返回值
    public <T> T getFirst(List<T> list) {
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }
    
    // 静态泛型方法
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }
}

// 使用
GenericMethod gm = new GenericMethod();
gm.print("Hello");
gm.print(100);

List<String> names = Arrays.asList("张三", "李四");
String first = gm.getFirst(names);

类型通配符

无界通配符 ?

java
public void printList(List<?> list) {
    for (Object element : list) {
        System.out.println(element);
    }
    // list.add("test");  // 编译错误,不能添加元素(除了null)
}

// 使用
List<String> strings = Arrays.asList("A", "B");
List<Integer> integers = Arrays.asList(1, 2);
printList(strings);
printList(integers);

上界通配符 <? extends T>

java
// 只能读取,不能写入(除了null)
public double sum(List<? extends Number> list) {
    double total = 0;
    for (Number num : list) {
        total += num.doubleValue();
    }
    return total;
}

// 使用
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.5, 2.5);
System.out.println(sum(integers));  // 6.0
System.out.println(sum(doubles));   // 4.0

下界通配符 <? super T>

java
// 只能写入T或T的子类,读取为Object
public void addNumbers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
    list.add(3);
}

// 使用
List<Number> numbers = new ArrayList<>();
addNumbers(numbers);
System.out.println(numbers);  // [1, 2, 3]

List<Object> objects = new ArrayList<>();
addNumbers(objects);

PECS原则

Producer Extends, Consumer Super

  • 生产者(读取):使用 ? extends T
  • 消费者(写入):使用 ? super T
java
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
    for (int i = 0; i < src.size(); i++) {
        dest.set(i, src.get(i));
    }
}

泛型擦除

Java泛型是编译时特性,运行时类型信息被擦除。

java
public class ErasureDemo {
    public static void main(String[] args) {
        List<String> strings = new ArrayList<>();
        List<Integer> integers = new ArrayList<>();
        
        // 运行时类型相同
        System.out.println(strings.getClass() == integers.getClass());  // true
        
        // 泛型信息被擦除
        System.out.println(strings.getClass());  // class java.util.ArrayList
    }
}

擦除规则

  • 无界类型参数 <T> 擦除为 Object
  • 有界类型参数 <T extends Number> 擦除为 Number
  • 多边界 <T extends A & B> 擦除为第一个边界 A

泛型限制

不能使用基本类型

java
// 错误
// List<int> list = new ArrayList<>();

// 正确:使用包装类
List<Integer> list = new ArrayList<>();

不能创建泛型数组

java
// 错误
// T[] array = new T[10];

// 正确:使用Object数组或反射
@SuppressWarnings("unchecked")
T[] array = (T[]) new Object[10];

不能实例化泛型

java
public class Factory<T> {
    // 错误
    // T instance = new T();
    
    // 正确:传入Class对象或Supplier
    public T create(Class<T> clazz) throws Exception {
        return clazz.getDeclaredConstructor().newInstance();
    }
}

不能抛出或捕获泛型类

java
// 错误
// public class MyException<T> extends Exception { }

// 错误
// try { } catch (T e) { }

泛型实战示例

泛型容器

java
public class Container<T> {
    private T value;
    
    public Container() { }
    
    public Container(T value) {
        this.value = value;
    }
    
    public T get() { return value; }
    public void set(T value) { this.value = value; }
    
    public boolean isPresent() {
        return value != null;
    }
    
    public <U> Container<U> map(Function<T, U> mapper) {
        return new Container<>(mapper.apply(value));
    }
}

泛型工具方法

java
public class GenericUtils {
    // 交换数组元素
    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>> T max(List<T> list) {
        if (list.isEmpty()) {
            return null;
        }
        T max = list.get(0);
        for (T item : list) {
            if (item.compareTo(max) > 0) {
                max = item;
            }
        }
        return max;
    }
    
    // 类型转换
    public static <T> List<T> castList(Class<T> clazz, List<?> list) {
        List<T> result = new ArrayList<>();
        for (Object item : list) {
            result.add(clazz.cast(item));
        }
        return result;
    }
}

泛型Builder模式

java
public class Person {
    private String name;
    private Integer age;
    private String city;
    
    private Person() { }
    
    public static <T> Builder<T> builder() {
        return new Builder<>();
    }
    
    public static class Builder<T> {
        private Person person = new Person();
        
        public Builder<T> name(String name) {
            person.name = name;
            return this;
        }
        
        public Builder<T> age(Integer age) {
            person.age = age;
            return this;
        }
        
        public Builder<T> city(String city) {
            person.city = city;
            return this;
        }
        
        public Person build() {
            return person;
        }
    }
}