当前位置: 首页 > news >正文

Java 泛型详解

在 Java 的类型系统中,泛型(Generics) 是一个非常重要的特性。它让我们能够编写更通用、更安全的代码,尤其是在处理集合类(如 ListMap 等)时,泛型的使用可以大大减少类型转换的麻烦,并在编译阶段捕获类型错误。本文将带你系统地了解 Java 泛型的概念、语法、使用方式、边界、通配符和原理。


一、什么是泛型?

泛型就是参数化类型。所谓参数化类型,就是将类型参数化,就像方法可以传入不同的参数一样,类和方法也可以传入“类型参数”。这样我们可以用同一份代码操作多种类型,而不必为了支持不同类型写多个重复的代码逻辑。

举个例子:

// 没有泛型的写法
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); // 不需要强制转换,类型安全

二、泛型的语法

1. 泛型类

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("泛型示例");
String content = stringBox.getContent();

2. 泛型方法

public class Utils {public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}
}

调用:

String[] strings = {"Java", "C++", "Python"};
Utils.printArray(strings);

3. 泛型接口

public interface Generator<T> {T next();
}

实现类:

public class StringGenerator implements Generator<String> {public String next() {return "Hello";}
}

三、泛型的边界:extends 和 super

1. 上界通配符(<? extends T>

表示参数类型是 T 或 T 的子类。常用于读取数据时:

public void print(List<? extends Number> list) {for (Number n : list) {System.out.println(n);}
}

你可以传入 List<Integer>List<Double> 等。

2. 下界通配符(<? super T>

表示参数类型是 T 或 T 的父类。常用于写入数据时:

public void add(List<? super Integer> list) {list.add(10); // 可以添加 Integer 或其子类
}

你可以传入 List<Object>List<Number> 等。


四、通配符 <?> 的使用

<?> 表示不确定的类型,它是所有泛型的父类。适用于只读的场景,例如:

public void printList(List<?> list) {for (Object obj : list) {System.out.println(obj);}
}

你不能向 List<?> 添加任何元素(除了 null),因为编译器无法确定类型安全。


五、类型擦除与泛型的本质

Java 的泛型采用**类型擦除机制(Type Erasure)**来实现:编译器在编译阶段会将泛型信息擦除,在字节码中不保留泛型信息。

举个例子:

Box<String> stringBox = new Box<>();
Box<Integer> intBox = new Box<>();

在编译后,这两种类型都会变成原始类型 Box。所以在运行时:

stringBox.getClass() == intBox.getClass(); // true

这也就是为什么 Java 中不能使用泛型数组的原因:

List<String>[] listArray = new List<String>[10]; // 编译错误

六、泛型的限制与注意事项

  1. 不能使用基本类型作为泛型参数

    Box<int> box = new Box<>(); // 编译错误
    // 使用包装类代替
    Box<Integer> box = new Box<>();
    
  2. 不能创建泛型数组

    T[] array = new T[10]; // 编译错误
    
  3. 不能实例化泛型类型参数

    T obj = new T(); // 编译错误
    
  4. 静态方法中不能引用类的泛型参数
    泛型参数是实例级别的,静态方法不属于实例。


七、泛型的实际应用场景

  1. 集合类(Collections Framework)
    所有集合类如 List<T>Map<K, V> 都使用了泛型。

  2. 通用工具类
    例如 Collections.sort(List<T> list) 使用泛型做排序。

  3. DAO 层的抽象类或接口
    泛型使得我们可以编写通用的数据访问逻辑,如:

    public interface BaseDao<T> {T findById(int id);void save(T entity);
    }
    

八、泛型的高级技巧

1. 多个泛型参数

public class Pair<K, V> {private K key;private V value;// 省略 getter/setter
}

2. 泛型限定符(bounded type parameter)

public <T extends Comparable<T>> T max(T a, T b) {return a.compareTo(b) > 0 ? a : b;
}

3. 捕获通配符

public void swap(List<?> list, int i, int j) {swapHelper(list, i, j);
}private <T> void swapHelper(List<T> list, int i, int j) {T temp = list.get(i);list.set(i, list.get(j));list.set(j, temp);
}

总结

泛型是 Java 提供的强大特性,它的核心目标是提升代码的重用性类型安全性。通过泛型,我们可以:

  • 编写可复用的类、接口和方法;

  • 编译期检查类型安全;

  • 减少类型转换的代码量。

掌握泛型,对于写出优雅、高质量的 Java 代码至关重要。希望本文能帮助你全面理解泛型的原理与实践!

相关文章:

  • VR 互动实训与展示,借科技开启沉浸式体验新篇​
  • 使用excel 工具做数据清洗
  • excel:时间戳格式与日期格式的互转
  • vue2.0 组件之间的数据共享
  • nginx 漏洞修复 CVE-2024-7347 CVE-2025-23419
  • Java实现PDF加水印功能:技术解析与实践指南
  • luckysheet的使用——17.将表格作为pdf下载到本地
  • Node-Red通过Profinet转ModbusTCP采集西门子PLC数据配置案例
  • BGP综合实验(2)
  • 高项-挣值管理TCPI
  • 软件设计师“测试用例”考点分析——求三连
  • ip与mac-数据包传输过程学习
  • 社交平台推出IP关联机制:增强用户体验与网络安全的新举措
  • 紫光同创FPGA实现AD9238数据采集转UDP网络传输,分享PDS工程源码和技术支持和QT上位机
  • 解决报错 Flask-SQLAlchemy TypeError: ‘float‘ object is not callable
  • Linux内核深入学习(4)——内核常见的数据结构之链表
  • WebRTC技术EasyRTC嵌入式音视频通信SDK助力智能电视搭建沉浸式实时音视频交互
  • 正点原子STM32新建工程
  • 容器化-K8s-镜像仓库使用和应用
  • 【Linux学习】Ubuntu对用户进行管理
  • 中国田径巡回赛西安站完赛:男子跳远石雨豪夺冠
  • 网警打谣:传播涉刘国梁不实信息,2人被处罚
  • 高飞已任南航集团党组副书记
  • 官方通报汕头违建豪宅“英之园”将强拆:对有关人员严肃追责问责
  • 习近平就乌拉圭前总统穆希卡逝世向乌拉圭总统奥尔西致唁电
  • 本周看啥|《歌手》今晚全开麦直播,谁能斩获第一名?