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

理解Java泛型

Java 泛型详解:类型安全与代码复用的完美结合

泛型(Generics)是 Java 5 引入的一项重要特性,它提供了编译时类型安全检测机制,允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

一、为什么需要泛型?

在 Java 5 之前,集合类如 ArrayList 可以存储任意类型的对象,这导致了以下问题:

  1. 类型不安全:可以向集合中添加任意类型的对象,在运行时可能引发 ClassCastException。
  2. 强制类型转换:从集合中获取对象时需要进行强制类型转换,增加了代码的复杂度和出错机会。

示例:非泛型集合的问题

import java.util.ArrayList;
import java.util.List;public class NonGenericExample {public static void main(String[] args) {List list = new ArrayList();list.add("Hello");list.add(123); // 编译时不会报错// 运行时会抛出ClassCastExceptionString str = (String) list.get(1); // 错误:无法将Integer转换为String}
}

泛型概述小结

与使用 Object 对象代替一切引用数据类型对象这样简单粗暴方式相比,泛型使得数据类型的类别可以像参数一样由外部传递进来。它提供了一种扩展能力,更符合面向对象开发的软件编程宗旨。
当具体的数据类型确定后,泛型又提供了一种类型安全检测机制,只有数据类型相匹配的变量才能正常的赋值,否则编        译器就不通过。所以说,泛型一定程度上提高了软件的安全性,防止出现低级的失误。
泛型提高了程序代码的可读性。在定义泛型阶段(类、接口、方法)或者对象实例化阶段,由于 < 类型参数 > 需要在代码中显式地编写,所以程序员能够快速猜测出代码所要操作的数据类型,提高了代码可读性。

二、泛型的基本语法

泛型类和泛型方法的定义使用尖括号<>来指定类型参数。

1. 泛型类

public class Box<T> {private T content;public void set(T content) {this.content = content;}public T get() {return content;}
}

使用泛型类

Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String str = stringBox.get(); // 无需强制类型转换Box<Integer> intBox = new Box<>();
intBox.set(123);
Integer num = intBox.get();

使用泛型类需要注意:泛型类中的静态方法和静态变量不可以使用泛型类所声明的类型参数,因为静态变量和静态方法在类加载的时候已经初始化,可以直接使用类名调用,没有声明类型就直接调用显然不符合规范

2. 泛型方法

public class GenericMethodExample {public static <T> void printArray(T[] array) {for (T element : array) {System.out.print(element + " ");}System.out.println();}public static void main(String[] args) {Integer[] intArray = {1, 2, 3};String[] strArray = {"Hello", "World"};printArray(intArray); // 输出: 1 2 3printArray(strArray); // 输出: Hello World}
}
三、泛型通配符

泛型通配符用于处理未知类型,主要有三种形式:

  1. 无界通配符<?>
  2. 上界通配符<? extends T>
  3. 下界通配符<? super T>

示例:通配符的使用

import java.util.ArrayList;
import java.util.List;public class WildcardExample {// 无界通配符public static void printList(List<?> list) {for (Object element : list) {System.out.print(element + " ");}System.out.println();}// 上界通配符:只能处理Number及其子类public static double sumOfList(List<? extends Number> list) {double sum = 0.0;for (Number n : list) {sum += n.doubleValue();}return sum;}// 下界通配符:只能处理Integer及其父类public static void addIntegers(List<? super Integer> list) {for (int i = 1; i <= 5; i++) {list.add(i);}}public static void main(String[] args) {List<Integer> intList = List.of(1, 2, 3);List<String> strList = List.of("A", "B", "C");printList(intList); // 输出: 1 2 3printList(strList); // 输出: A B CList<Double> doubleList = List.of(1.5, 2.5, 3.5);System.out.println(sumOfList(doubleList)); // 输出: 7.5List<Object> objList = new ArrayList<>();addIntegers(objList);System.out.println(objList); // 输出: [1, 2, 3, 4, 5]}
}
四、泛型边界

泛型边界用于限制泛型类型参数的范围,可以是类边界或接口边界。

示例:泛型边界的使用

// 泛型类的边界
public class ComparableBox<T extends Comparable<T>> {private T content;public ComparableBox(T content) {this.content = content;}public T getMax(T other) {return (content.compareTo(other) >= 0) ? content : other;}
}// 使用
ComparableBox<Integer> box = new ComparableBox<>(10);
Integer max = box.getMax(20); // 返回20
五、类型擦除

Java 泛型是通过类型擦除(Type Erasure)实现的。在编译过程中,泛型类型信息会被擦除,替换为它们的边界类型(或 Object 如果没有指定边界)。

示例:类型擦除

// 编译前
List<String> stringList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();// 编译后(类型擦除)
List stringList = new ArrayList();
List intList = new ArrayList();
六、泛型的限制
  1. 不能实例化泛型类型T obj = new T(); // 错误
  2. 不能创建泛型数组T[] array = new T[10]; // 错误
  3. 静态上下文中不能使用泛型类型参数
  4. 不能捕获或抛出泛型类型的异常
七、泛型的最佳实践
  1. 使用有意义的类型参数名称:如T(Type)、K(Key)、V(Value)等。
  2. 优先使用泛型方法而非原始类型
  3. 利用通配符提高代码灵活性
  4. 理解类型擦除的影响

泛型是 Java 语言中一项强大的特性,它增强了代码的类型安全性和复用性,减少了强制类型转换,是现代 Java 编程中不可或缺的一部分。掌握泛型的使用和原理,对于编写高质量的 Java 代码至关重要。

http://www.xdnf.cn/news/7763.html

相关文章:

  • 直流无刷水泵方案之无感FOC控制---【其利天下技术】
  • StreamSaver实现大文件下载解决方案
  • 对象属性复制BeanCopier-笔记
  • 基于正点原子阿波罗F429开发板的LWIP应用(2)——设置静态IP和MAC地址修改
  • Python代码加密与发布方案详解
  • SpringMVC04所有注解按照使用位置划分| 按照使用层级划分(业务层、视图层、控制层)
  • MCP模型上下文协议:基于FastMCP 2.0的实践(2)
  • 机器学习第十九讲:交叉验证 → 用五次模拟考试验证真实水平
  • Linux基础IO(二)
  • upload-labs通关笔记-第14关 文件上传之文件头绕过(图片马)
  • 建筑墙壁红外热成像裂缝潮湿检测数据集VOC+YOLO格式306张2类别
  • 【项目】—高并发内存池
  • AUTOSAR图解==>AUTOSAR_SRS_SAEJ1939
  • day16-17-磁盘管理
  • 流程控制-循环
  • Robot Studio开发入门指南
  • 频分复用信号在信道中的状态
  • 第11天-Python GUI开发实战:Tkinter从入门到项目实践
  • 鸿蒙开发进阶:深入解析ArkTS语言特性与高性能编程实践
  • 【设计模式】基于 Java 语言实现工厂模式
  • 第二届帕鲁杯时间折叠(TimeFold Paradox)
  • 绝缘栅双极型晶体管IGBT的结构与特点
  • 【Git】常用命令大全
  • Git的windows开发与linux开发配置
  • Dify快速上手 MCP,接入高德地图 Server 实战攻略
  • 香港科技大学物理学理学(科学计算与先进材料物理与技术)硕士招生宣讲会——深圳大学
  • 制作一款打飞机游戏52:子弹模式
  • C++显式声明explicit
  • 1G(第一代移动通信系统)详解
  • python 提交 命令到远程windows服务器并获取作业进程id