Java泛型

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


一、泛型的核心作用

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

二、基本语法

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

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

    public T getContent() {
        return content;
    }
}

使用示例:

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

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

使用示例:

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

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

实现示例:

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

三、类型限定(边界)

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

使用:

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

使用:

java 复制代码
List<Number> numbers = new ArrayList<>();
addNumbers(numbers); // ✅ Number 是 Integer 的父类
3. 类型参数边界
java 复制代码
// 要求 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
  • 编译器自动插入强制类型转换

示例:

java 复制代码
// 编译前
Box<String> box = new Box<>();
String s = box.getContent();

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

五、使用限制

  1. 不能实例化泛型类型

    java 复制代码
    T obj = new T(); // ❌ 编译错误
  2. 不能创建泛型数组

    java 复制代码
    T[] array = new T[10]; // ❌ 错误
  3. 静态成员不能使用类型参数

    java 复制代码
    private static T staticVar; // ❌ 错误
  4. 基本类型不可作为类型参数

    java 复制代码
    // Box<int> box = new Box<>(); ❌ 错误
    Box<Integer> box = new Box<>(); // ✅ 使用包装类

六、最佳实践

  1. 优先使用泛型方法:当方法独立于类泛化时更灵活

  2. 使用 List 而非数组:避免泛型数组问题

  3. 合理使用通配符

    • Producer-Extends, Consumer-Super(PECS原则)
  4. 避免原生类型

    java 复制代码
    List list = new ArrayList(); // ❌ 原生类型(有警告)
    List<String> list = new ArrayList<>(); // ✅

七、完整示例

java 复制代码
// 泛型类 + 类型限定
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 实现了类型安全的通用编程,显著提升了代码质量和可维护性。

相关推荐
皮皮林5511 小时前
SpringBoot 全局/局部双模式 Gzip 压缩实战:14MB GeoJSON 秒变 3MB
java·spring boot
weixin_456904272 小时前
Spring Boot 用户管理系统
java·spring boot·后端
趁你还年轻_2 小时前
异步编程CompletionService
java
DKPT2 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
sibylyue2 小时前
Guava中常用的工具类
java·guava
奔跑吧邓邓子2 小时前
【Java实战㉞】从0到1:Spring Boot Web开发与接口设计实战
java·spring boot·实战·web开发·接口设计
专注API从业者2 小时前
Python/Java 代码示例:手把手教程调用 1688 API 获取商品详情实时数据
java·linux·数据库·python
奔跑吧邓邓子2 小时前
【Java实战㉝】Spring Boot实战:从入门到自动配置的进阶之路
java·spring boot·实战·自动配置
ONLYOFFICE2 小时前
【技术教程】如何将ONLYOFFICE文档集成到使用Spring Boot框架编写的Java Web应用程序中
java·spring boot·编辑器
叫我阿柒啊3 小时前
Java全栈开发工程师的实战面试经历:从基础到微服务
java·微服务·typescript·vue·springboot·前端开发·后端开发