Java泛型

发布于:2025-07-29 ⋅ 阅读:(13) ⋅ 点赞:(0)

在 Java 中,泛型(Generics) 是一种允许在定义类、接口或方法时使用类型参数的特性。它的核心目的是增强类型安全性、减少类型转换错误,并提高代码复用性。下面通过关键概念和示例详细解释:


一、泛型的核心作用

  1. 类型安全:编译时检查类型错误,避免运行时 ClassCastException
  2. 消除强制类型转换:代码更简洁
  3. 代码复用:一套逻辑可处理多种数据类型

二、基本语法

1. 泛型类
// T 是类型参数(可自定义名称)
public class Box<T> {
    private T content;

    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }
}

使用示例:

Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String value = stringBox.getContent(); // 无需强制转换

Box<Integer> intBox = new Box<>();
intBox.setContent(100);
2. 泛型方法
public <T> void printArray(T[] array) {
    for (T item : array) {
        System.out.print(item + " ");
    }
}

使用示例:

String[] strs = {"A", "B", "C"};
printArray(strs); // 自动推断 T 为 String

Integer[] ints = {1, 2, 3};
printArray(ints); // T 为 Integer
3. 泛型接口
public interface Repository<T> {
    void save(T entity);
    T findById(int id);
}

实现示例:

public class UserRepository implements Repository<User> {
    @Override
    public void save(User user) { /* ... */ }
    
    @Override
    public User findById(int id) { /* ... */ }
}

三、类型限定(边界)

1. 上界通配符 <? extends T>
  • 接受 T 或其子类型
// 只能读取数据(安全)
public double sum(List<? extends Number> list) {
    double total = 0;
    for (Number num : list) {
        total += num.doubleValue();
    }
    return total;
}

使用:

List<Integer> ints = List.of(1, 2, 3);
sum(ints); // ✅ Integer 是 Number 的子类
2. 下界通配符 <? super T>
  • 接受 T 或其父类型
// 可写入数据(安全)
public void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 5; i++) {
        list.add(i);
    }
}

使用:

List<Number> numbers = new ArrayList<>();
addNumbers(numbers); // ✅ Number 是 Integer 的父类
3. 类型参数边界
// 要求 T 必须实现 Comparable 接口
public <T extends Comparable<T>> T max(T a, T b) {
    return a.compareTo(b) > 0 ? a : b;
}

四、类型擦除(重要机制)

Java 泛型在编译后会被擦除,转换为原始类型:

  • 泛型类 Box<T> → 运行时变为 Box(原始类型)
  • 类型参数 T → 替换为 Object 或边界类型(如 T extends Number 则替换为 Number
  • 编译器自动插入强制类型转换

示例:

// 编译前
Box<String> box = new Box<>();
String s = box.getContent();

// 编译后(等效代码)
Box box = new Box();
String s = (String) box.getContent(); // 编译器添加的类型转换

五、使用限制

  1. 不能实例化泛型类型
    T obj = new T(); // ❌ 编译错误
    
  2. 不能创建泛型数组
    T[] array = new T[10]; // ❌ 错误
    
  3. 静态成员不能使用类型参数
    private static T staticVar; // ❌ 错误
    
  4. 基本类型不可作为类型参数
    // Box<int> box = new Box<>(); ❌ 错误
    Box<Integer> box = new Box<>(); // ✅ 使用包装类
    

六、最佳实践

  1. 优先使用泛型方法:当方法独立于类泛化时更灵活
  2. 使用 List 而非数组:避免泛型数组问题
  3. 合理使用通配符
    • Producer-Extends, Consumer-Super(PECS原则)
  4. 避免原生类型
    List list = new ArrayList(); // ❌ 原生类型(有警告)
    List<String> list = new ArrayList<>(); // ✅
    

七、完整示例

// 泛型类 + 类型限定
public class Container<T extends Number> {
    private T value;
    
    public Container(T value) {
        this.value = value;
    }
    
    // 泛型方法
    public <U extends Number> boolean isEqual(U other) {
        return this.value.doubleValue() == other.doubleValue();
    }
}

// 使用
Container<Double> container = new Container<>(3.14);
boolean result = container.isEqual(3.14f); // ✅ 比较 Double 和 Float

通过泛型,Java 实现了类型安全的通用编程,显著提升了代码质量和可维护性。


网站公告

今日签到

点亮在社区的每一天
去签到