Java 泛型 简学

39 阅读2分钟

一、一句话理解

泛型 = 类型参数化,让代码更安全、可复用

二、核心语法

1. 类泛型

// 定义
class Box<T> {          // T: 类型参数
    private T content;
    
    void set(T content) { this.content = content; }
    T get() { return content; }
}

// 使用
Box<String> box = new Box<>();  // 具体类型:String
box.set("Hello");
String s = box.get();           // 无需强制转换

2. 方法泛型

// 定义
<T> T getFirst(List<T> list) {  // <T>在返回值前
    return list.get(0);
}

// 使用
String first = getFirst(Arrays.asList("A", "B"));  // 自动推断T为String

3. 接口泛型

// 定义
interface Pair<K, V> {          // 多个类型参数
    K getKey();
    V getValue();
}

// 实现
class StringIntegerPair implements Pair<String, Integer> {
    public String getKey() { return "age"; }
    public Integer getValue() { return 25; }
}

三、类型通配符

1. ? 无界通配符

// 接收任何类型的List
void printList(List<?> list) {  // ?表示任意类型
    for (Object elem : list) {
        System.out.println(elem);
    }
}

2. ? extends T 上界通配符

// 接收T及其子类型的List
void processNumbers(List<? extends Number> list) {  // Number或其子类
    // 可以读取为Number
    Number n = list.get(0);
    // ❌ 不能添加(不知道具体子类型)
    // list.add(new Integer(1));  // 编译错误
}

3. ? super T 下界通配符

// 接收T及其父类型的List
void addNumbers(List<? super Integer> list) {  // Integer或其父类
    // 可以添加Integer及其子类
    list.add(10);
    // ❌ 读取时只能得到Object
    Object obj = list.get(0);
}

四、关键限制

1. 类型擦除

// 编译时:Box<String>
// 运行时:Box<Object>(类型信息被擦除)

Box<String> box1 = new Box<>();
Box<Integer> box2 = new Box<>();
System.out.println(box1.getClass() == box2.getClass()); // true

2. 不能做的事

// ❌ 不能创建泛型数组
T[] array = new T[10];  // 错误

// ❌ 不能实例化类型参数
T obj = new T();        // 错误

// ❌ 不能用于静态上下文
class Box<T> {
    // static T content;  // 错误
}

五、实际应用

1. 集合框架

// 没有泛型(JDK 1.5前)
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);  // 需要强制转换

// 有泛型
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0);           // 自动类型安全

2. 工具方法

// 安全地交换数组元素
static <T> void swap(T[] array, int i, int j) {
    T temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}

// 找出最大值
static <T extends Comparable<T>> T max(T a, T b) {
    return a.compareTo(b) > 0 ? a : b;
}

六、记忆口诀

  1. PECS原则(Producer Extends, Consumer Super)

    • 生产者extends(只能取)
    • 消费者super(只能存)
  2. 使用时机

    • 类/方法要处理多种类型 → 用泛型
    • 要保证类型安全 → 用泛型
    • 避免强制类型转换 → 用泛型

七、简单示例

// 1. 泛型类
class Container<T> {
    private T item;
    public void put(T item) { this.item = item; }
    public T get() { return item; }
}

// 2. 泛型方法
class Utils {
    public static <T> boolean isEqual(T a, T b) {
        return a.equals(b);
    }
}

// 3. 泛型接口
interface Transformer<T, R> {
    R transform(T input);
}

总结

泛型 = 让编译器帮我们检查类型安全,减少运行时错误,让代码更通用。