泛型擦除注意点

代码如下:

 ArrayList<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog());
        ArrayList list=dogs;
        System.out.println(list==dogs);
        //泛型擦出
        list.add(new Cat());
        System.out.println("dog size"+dogs.size());
        System.out.println("list size"+list.size());
        System.out.println(list==dogs);

运行结果如下:

可以看到其实添加泛型并没有从本质上更改arraylist对象中存储的数据的类型,仅仅只是在当前引用上加上了一层限制。

### Java List擦除的实现原理 Java中的是一种编译时机制,用于提供更强的类安全性。然而,在运行时,JVM并不直接支持;这意味着所有与相关的类信息都会被编译器在编译阶段移除,这一过程被称为**类擦除**。通过这种方式,Java能够保持向后兼容性,并且不需要修改JVM来支持新的特性[^1]。 以`List<String>`为例,尽管开发者可以在代码中声明这样的列表并仅向其中添加字符串对象,但在编译后的字节码中,这种信息会被擦除,实际的类会变成原始类`List`。因此,从运行时的角度来看,`List<String>`和普通的`List`没有区别,它们都被视为存储`Object`类的集合[^2]。 #### 类擦除的具体表现 当一个类如`ArrayList<T>`被编译时,其中的参数`T`会被替换为它的上界(如果未指定,则默认为`Object`)。例如,下面的源码: ```java public class Box<T> { private T value; public void set(T value) { this.value = value; } public T get() { return value; } } ``` 经过编译之后等效于: ```java public class Box { private Object value; public void set(Object value) { this.value = value; } public Object get() { return value; } } ``` 这表明,无论`Box`实例化时使用的具体类是什么,其内部成员变量`value`以及方法参数都将被视为`Object`处理。同样地,对于`List<Integer>`或任何其他具体的实例化,最终也会变成基于`Object`的操作[^5]。 #### 反射与类擦除 由于类擦除的存在,使用反射API获取的实际类信息变得复杂。比如尝试通过`getClass().getTypeParameters()`获取`List<Integer>`的参数时,只会得到占位符`[E]`而非实际的`Integer`类。这是因为这些信息只存在于编译时期,而在运行时已经被擦除了[^3]。 但是,利用反射仍然可以绕过编译器对的限制。考虑以下示例: ```java ArrayList<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); // 通过反射绕过编译 Class clazz = list.getClass(); Method method = clazz.getMethod("add", Object.class); // 注意这里必须使用Object.class作为参数类 method.invoke(list, 21); // 向列表中添加一个整数 System.out.println(list); // 输出结果包含了一个Integer元素 ``` 这段代码展示了如何通过反射调用`add`方法并向一个原本应该只能容纳字符串的列表中插入了一个整数。虽然这样做违反了的设计意图,但它确实证明了类擦除使得此类操作成为可能[^3]。 #### 影响与注意事项擦除带来的主要影响之一是失去了运行时的类检查能力。这意味着即使是在编译期间通过确保了类安全,在某些情况下也可能因为反射或其他手段导致不正确的类被插入到集合中。此外,这也意味着无法创建具有特定的数组,除非提供了适当的类令牌或者采取其他变通措施。 综上所述,Java的设计旨在提供一种轻量级的、编译时的类检查机制,而类擦除则是其实现方式的关键部分。理解这一有助于更好地把握Java语言的本质特征及其局限性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值