反射能往ArrayList加"hello"是因为泛型是编译期语法糖,add方法字节码签名实为add(Object),JVM运行时无泛型信息,反射调用getMethod("add", Object.class)绕过编译检查成功执行。

不能真正“绕过”泛型检查,只能在运行时跳过编译期的类型约束;但添加后读取时会因类型擦除+强制转型而抛 ClassCastException。
为什么反射能往 ArrayList<integer></integer> 里加 "hello"
泛型是编译期语法糖,ArrayList.add(E) 在字节码里实际签名就是 add(Object)。JVM 运行时看不到 Integer,所以反射调用 getMethod("add", Object.class) 能成功执行 —— 它压根不校验泛型。
- 编译器阻止你写
array.add("hello"),但反射走的是 JVM 方法查找路径,绕开了 javac 的语义检查 -
array.getClass().getMethod("add", Object.class)拿到的是原始方法,参数类型擦除后就是Object - 添加动作本身不会失败,集合内部存储的是
Object[],字符串对象可以正常塞进去
加进去之后,get() 或遍历时会出什么问题
读取时才会暴露问题:泛型集合的 get(int) 返回值被声明为 E(如 Integer),但实际返回的是 String,JVM 在返回前自动插入 checkcast Integer 字节码,触发转型失败。
-
array.get(0)表面返回Integer,底层执行的是return (Integer) elementData[0] - 如果
elementData[0]是"hello",强转String → Integer直接抛ClassCastException - 用
for (Object o : array)遍历能拿到字符串,但一旦尝试(Integer) o就崩
getMethod 和 getDeclaredMethod 选哪个
对 ArrayList.add() 这种 public 方法,用 getMethod 就够了;但要注意它只查继承链上的 public 方法,而 getDeclaredMethod 查本类所有(含 private),一般不需要。
-
getMethod("add", Object.class)✅ 正确,add是 public 方法 -
getDeclaredMethod("add", Object.class)❌ 不必要,且若方法被重载可能匹配不准 - 别漏掉参数类型:必须传
Object.class,传String.class会找不到方法
真正危险的不是加数据,而是后续按泛型类型去用——类型擦除让 JVM 在读取时才做不可靠的转型,这时候报错已经晚了。

















