🎬 HoRain云小助手:个人主页
🔥 个人专栏: 《Linux 系列教程》《c语言教程》
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
专栏介绍
专栏名称 | 专栏介绍 |
《C语言》 | 本专栏主要撰写C干货内容和编程技巧,让大家从底层了解C,把更多的知识由抽象到简单通俗易懂。 |
《网络协议》 | 本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘,一起解密网络协议在运行中协议的基本运行机制! |
《docker容器精解篇》 | 全面深入解析 docker 容器,从基础到进阶,涵盖原理、操作、实践案例,助您精通 docker。 |
《linux系列》 | 本专栏主要撰写Linux干货内容,从基础到进阶,知识由抽象到简单通俗易懂,帮你从新手小白到扫地僧。 |
《python 系列》 | 本专栏着重撰写Python相关的干货内容与编程技巧,助力大家从底层去认识Python,将更多复杂的知识由抽象转化为简单易懂的内容。 |
《试题库》 | 本专栏主要是发布一些考试和练习题库(涵盖软考、HCIE、HRCE、CCNA等) |
目录
⛳️ 推荐
专栏介绍
一、泛型的核心作用
1. 强制编译期类型安全检查
2. 消除显式类型转换
3. 提升代码复用性与可读性
二、泛型的三种主要使用方式
1. 泛型类
2. 泛型方法
3. 泛型接口
三、通配符的关键特性
1. 上界通配符 ? extends T(协变)
2. 下界通配符 ? super T(逆变)
3. 无界通配符 ?
四、类型擦除机制
1. 核心原理
2. 关键影响
五、使用注意事项
Java 泛型是通过类型参数化实现编译期类型安全检查的机制,核心价值在于避免运行时类型转换错误(如ClassCastException),同时提升代码复用性与可读性。其本质是将类型作为参数传递,在编译阶段而非运行时验证数据类型一致性,但受类型擦除机制影响,运行时泛型信息会被擦除为原始类型(如List<String>擦除后为List)。以下从关键维度展开说明:
一、泛型的核心作用
1.强制编译期类型安全检查
- 使用泛型后,编译器会在代码编译阶段验证类型匹配性,而非等到运行时才发现错误。
例如:List<String>只能存储String类型,若尝试添加Integer,编译器会直接报错,避免运行时ClassCastException。 - 对比非泛型代码:
List list = new ArrayList(); list.add("Hello"); String str = (String) list.get(0); // 需手动强转,若误存其他类型会运行时报错
2.消除显式类型转换
- 泛型方法或集合在获取元素时自动完成类型转换,无需手动强转:
List<String> list = new ArrayList<>(); list.add("Hello"); String str = list.get(0); // 无需 (String) 强转 - 显著减少冗余代码,同时避免因遗漏强转导致的运行时异常。
3.提升代码复用性与可读性
- 一套泛型逻辑可适配多种类型(如
List<Integer>、List<String>共用ArrayList实现)。 - 代码直接体现类型约束(如
Map<Integer, String>明确键值类型),增强可维护性。
二、泛型的三种主要使用方式
1.泛型类
- 在类定义时声明类型参数,适用于需跨多个方法共享类型场景(如集合类):
public class Box<T> { private T value; public void setValue(T value) { this.value = value; } public T getValue() { return value; } } // 使用 Box<String> strBox = new Box<>(); strBox.setValue("Hello"); - 注意:静态成员无法引用类级别的泛型参数(如
static T field非法),因静态成员在类加载时初始化,而泛型类型由实例化时确定。
2.泛型方法
- 在方法签名中独立声明类型参数,适用于单次操作的类型通用化:
public static <T> void printArray(T[] array) { for (T item : array) System.out.print(item + " "); } // 调用时自动推断类型 printArray(new Integer[]{1, 2, 3}); printArray(new String[]{"A", "B"}); - 关键区别:泛型方法的
<T>位于返回值前,且类型参数作用域仅限该方法。
3.泛型接口
- 接口定义中使用类型参数,实现类需指定具体类型或传递泛型:
public interface Generator<T> { T generate(); } // 实现时指定类型 class NumberGenerator implements Generator<Integer> { public Integer generate() { return 100; } } - 常用于标准库(如
Comparable<T>、Iterator<T>)。
三、通配符的关键特性
1.上界通配符? extends T(协变)
- 表示
T或其子类型,适用于只读场景(可安全读取T类型数据):public static double sum(List<? extends Number> list) { double total = 0; for (Number num : list) total += num.doubleValue(); return total; } // 可传入 List<Integer>、List<Double> 等 - 限制:无法向集合中写入除
null外的任何元素(因编译器无法确定具体子类型)。
2.下界通配符? super T(逆变)
- 表示
T或其父类型,适用于只写场景(可安全写入T及其子类型):public static void addIntegers(List<? super Integer> list) { list.add(100); // 允许写入 Integer } // 可传入 List<Integer>、List<Number>、List<Object> - 限制:读取时只能得到
Object类型(因父类型不确定)。
3.无界通配符?
- 表示未知类型,适用于仅需调用与类型无关的方法(如
size()、clear()):public static void printSize(List<?> list) { System.out.println("Size: " + list.size()); }
四、类型擦除机制
1.核心原理
- Java 泛型通过编译期擦除类型信息实现,运行时所有泛型类型均退化为原始类型:
List<String>→ListList<Integer>→List
- 类型参数被替换为其上界(默认
Object),例如:class Pair<T extends Comparable<T>> { ... } // 擦除后等效于 class Pair { Comparable value; } - 擦除是为兼容 JVM 旧版本的设计选择,非缺陷。
2.关键影响
- 无法实例化泛型类型:
new T()非法(因运行时无T信息)。 - 无法使用
instanceof检查泛型类型:obj instanceof List<String>语法错误。 - 泛型数组不可创建:
new ArrayList<String>编译失败(但new ArrayList<?>允许)。
五、使用注意事项
- 泛型仅支持引用类型:
基本类型需用包装类(如List<Integer>而非List<int>)。 - 避免原始类型(Raw Type):
List list = new ArrayList()会绕过编译检查,应始终显式指定泛型参数。 - 通配符的读写限制:
? extends T适合读取,? super T适合写入,遵循 PECS 原则(Producer-extends, Consumer-super)。
- 运行时类型安全需额外保障:
通过反射或跨模块传递数据时,需手动校验类型(如clazz.isInstance(item)),因擦除后无泛型信息。
泛型是 Java 集合框架与类型安全的基石,合理使用可显著提升代码质量,但需深刻理解其擦除机制以规避隐式类型风险。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙