一、擦拭法:Java泛型的底层魔术
Java泛型的核心机制是类型擦除(Type Erasure)。编译器在编译阶段移除所有泛型类型信息:
- 无界类型参数(如
<T>)替换为Object - 有界类型参数(如
<T extends Number>)替换为边界类型(Number) - 生成桥接方法保持多态性(如
Comparable接口实现)
java
// 编译前
public class Box<T> {
private T content;
public void set(T item) { this.content = item; }
}
// 编译后(等效代码)
public class Box {
private Object content;
public void set(Object item) { this.content = item; }
}
二、擦拭法的双面刃:优势与代价
✅ 优势:
- 向后兼容:泛型代码可运行在旧版JVM(JDK 1.5+)
- 运行时高效:无额外类型检查开销
⚠️ 局限性:
|
问题 |
示例代码 |
原因 |
|
运行时类型丢失 |
// 编译错误 |
运行时只有 |
|
无法实例化泛型数组 |
// 错误 |
擦除后无法确定 类型 |
|
方法签名冲突 |
与 冲突 |
擦除后参数类型相同 |
三、突破擦拭法:反射的"后门"
虽然编译器严格检查类型,但反射可在运行时绕过限制:
java
List<Integer> intList = new ArrayList<>();
intList.add(123);
// 反射突破泛型类型检查
Method addMethod = intList.getClass().getMethod("add", Object.class);
addMethod.invoke(intList, "字符串数据"); // 注入String到Integer列表!
System.out.println(intList);
// 输出:[123, 字符串数据] -> 运行时无ClassCastException!
关键解析:intList运行时类型为原始ArrayList,其add(Object)方法可接受任意类型。编译器插入的类型转换只在取值时触发,注入时无检查。
四、高级技巧:保留泛型类型信息
通过类型令牌(Type Token) 可在运行时获取泛型参数:
java
public class GenericType<T> {
private final Type type;
public GenericType() {
this.type = ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
public Type getType() { return type; }
}
// 使用示例
Type stringType = new GenericType<String>() {}.getType();
System.out.println(stringType); // 输出:class java.lang.String
思考:Java的擦拭法如同魔术师的障眼法——编译期保障安全,却在运行时隐藏真相。这种设计虽成就了兼容性,却将类型安全的承诺半途而废。当开发者过度依赖编译器保护,反射的"破壁"操作便成为潜伏的炸弹。理解擦拭法的本质,方能在泛型的魔法与现实的约束间找到平衡。

被折叠的 条评论
为什么被折叠?



