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

相关推荐
慕y27414 分钟前
Java学习第七十二部分——Zookeeper
java·学习·java-zookeeper
midsummer_woo19 分钟前
基于spring boot的医院挂号就诊系统(源码+论文)
java·spring boot·后端
_Aaron___1 小时前
面向对象的三大特性---多态
java
Kiri霧1 小时前
IntelliJ IDEA
java·ide·kotlin·intellij-idea
daixin88481 小时前
什么是缓存雪崩?缓存击穿?缓存穿透?分别如何解决?什么是缓存预热?
java·开发语言·redis·缓存
京茶吉鹿1 小时前
"if else" 堆成山?这招让你的代码优雅起飞!
java·后端
你我约定有三1 小时前
RabbitMQ--消息丢失问题及解决
java·开发语言·分布式·后端·rabbitmq·ruby
张北北.2 小时前
【深入底层】C++开发简历4+4技能描述6
java·开发语言·c++
Java初学者小白2 小时前
秋招Day19 - 分布式 - 分布式事务
java·分布式
rannn_1112 小时前
Java学习|黑马笔记|Day23】网络编程、反射、动态代理
java·笔记·后端·学习