Java集合和数据结构-反射突破编译器类型检查
·

目录
这个例子展示的是"编译器的墙被反射打了个洞"。让我拆解给你看:
精简版(核心逻辑)
// 【正常写法】编译器严格把关,类型错误直接报错
myArray.add("字符串"); // ❌ 编译失败!编译器:你这是Integer容器!
// 【反射写法】编译器看不到反射里的操作,运行时JVM也不管类型
Method addMethod = MyArray.class.getMethod("add", Object.class); // 第1行
addMethod.invoke(myArray, "字符串"); // 第2行:✅ 运行成功!
// 结果:"字符串"真的被塞进了本该存Integer的myArray里!
关键结论:反射是运行时的"后门",编译器检查不到第2行传的是String,JVM运行期也无法阻止(因为内部就是Object[])。
详细版(逐行剖析反射如何"作弊")
背景:MyArray类长这样
public class MyArray<T> {
private Object[] data = new Object[10]; // 运行期T变成Object
public void add(T item) { // 运行期变成:add(Object item)
data[0] = item;
}
public T get(int index) { // 运行期变成:get()返回Object
return (T) data[index];
}
}
反射绕过过程(对应代码行)
// 第1行:通过反射获取add方法
// 【关键点】getMethod第一个参数是方法名"add"
// 第二个参数Object.class是擦除后的参数类型!
// 因为运行期add方法的签名实际上是:add(Object item),不是add(Integer item)
Method addMethod = MyArray.class.getMethod("add", Object.class);
// 此时addMethod指向的是"裸方法",它接受任何Object,不限于Integer
// 第2行:invoke调用方法
// 第一个参数myArray:要操作的对象(本该存Integer的那个)
// 第二个参数"字符串":实际传入的值(类型是String)
addMethod.invoke(myArray, "字符串");
// 【编译器视角】:这行代码编译时完全合法!
// 因为编译器只看到"invoke(Object obj, Object... args)"
// 它不知道你传的是myArray,也不知道"字符串"会进Integer容器
// 编译器:我只是看到反射调用,运行时的事我管不了
// 【JVM运行期视角】:
// 调用myArray.add(Object item),传入"字符串"
// 内部执行:data[0] = "字符串"; // 完全合法,因为data是Object[]
// JVM:我又不知道这个MyArray"应该"存Integer,擦除后就是Object[]
对比图:正常调用 vs 反射调用
| 维度 | 正常调用 myArray.add("str") | 反射调用 addMethod.invoke(myArray, "str") |
|
编译期 |
❌ 报错 编译器看到 |
✅ 通过 编译器只看到反射API,无法检查具体参数 |
|
运行期 |
不会执行到 |
✅ 执行成功 JVM看到的是 |
|
类型安全 |
编译器保证 |
❌ 无保障 你可能把"字符串"存进Integer容器,取出时抛出ClassCastException |
后果演示(为什么要避免这样做)
// 接上面反射插入"字符串"后:
MyArray<Integer> myArray = new MyArray<>();
// 通过反射塞入String(运行期成功)
addMethod.invoke(myArray, "我不是整数");
// 正常取出(编译器认为这是安全的,因为声明是<Integer>)
Integer num = myArray.get(0);
// 💥 运行时报错!ClassCastException: String cannot be cast to Integer
// 原因:get()方法里有编译器插入的强制转换 (Integer) data[0]
// 但data[0]实际是String,强转失败!
一句话总结:反射就像是在运行时偷偷摸摸操作,编译器在第36行建立的<Integer>规则管不到反射的"后门",JVM运行期又因为擦除机制分不清类型,结果就能把"字符串"硬塞进Integer专用盒子,等到取出来用时才发现炸了。
更多推荐



所有评论(0)