Java泛型类型擦除以及类型擦除带来的问题

简介: Java泛型在编译后会进行类型擦除,仅保留原始类型。例如,List<String>和List<Integer>在运行时均变为List,泛型信息不复存在。通过反射可向声明为Integer的列表添加字符串,证明泛型类型被擦除,JVM无法感知其原始泛型约束。

1.什么是泛型擦除

我们都知道Java的泛型是伪泛型,即编译期间所有的泛型信息都会被擦除,如我们代码定义了:List<Object>和List<String>,但是对于JVM而言,看到的只有List,由泛型附加的类型信息对于JVM而言是看不到的。代码说明如下:

1.1 原始类型擦除后相等

public class Test {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<String>();
        list1.add("abc");
        ArrayList<Integer> list2 = new ArrayList<Integer>();
        list2.add(123);
        System.out.println(list1.getClass() == list2.getClass());
    }
}

在这个例子中,我们定义了两个ArrayList数组,不过一个是ArrayList<String>泛型类型的,只能存储字符串;一个是ArrayList<Integer>泛型类型的,只能存储整数,最后,我们通过list1对象和list2对象的getClass()方法获取他们的类的信息,最后发现结果为true。说明泛型类型String和Integer都被擦除掉了,只剩下原始类型。

1.2 反射添加的元素被擦除

public static void main(String[] args) 
    throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(1);  //这样调用 add 方法只能存储整形,因为泛型类型的实例为 Integer
        list.getClass().getMethod("add", Object.class).invoke(list, "asd");
        for (int i = 0; i < list.size(); i++) {
            // 输出1  asd
            System.out.println(list.get(i));
        }
    }

如果直接调用add()方法,那么只能存储整数数据,不过当我们利用反射调用add()方法的时候,却可以存储字符串,这说明了Integer泛型实例在编译之后被擦除掉了,只保留了原始类型。

相关文章
|
XML JSON API
高效使用 Postman:如何正确传递 Query、Path 和 Body 参数
Postman 作为一个功能强大的工具,极大地简化了 API 测试和调试的过程,提供了发送请求和检查响应的直接方法。本文将着重介绍如何在 Postman 中高效地处理请求参数,以提高 API 测试和开发的便利性。
|
7月前
|
存储 运维 算法
【分布式】分布式系统核心知识体系:CAP定理、BASE理论与核心挑战
本文构建“理论边界→工程落地→现实挑战”闭环知识体系,深度解析CAP定理(分布式不可突破的不可能三角)、BASE理论(AP场景下的柔性实践)及八大类核心工程挑战,厘清误区,建立系统化认知框架。
|
人工智能 监控 安全
拔俗AI集成化管控平台:让智能应用“管得住、跑得稳”的技术底座
AI集成化管控平台是支撑AI规模化落地的“幕后基建”,涵盖资源调度、服务编排与全链路治理三大核心层,实现模型统一管理、服务标准化输出与系统稳定可控,助力企业构建高效、安全、可追溯的AI应用体系。
578 1
|
11月前
|
安全 Java 索引
说说 java 中常见的集合类
本文介绍了Java集合框架的核心接口(Collection、List、Set、Map)及其常见实现类。图示展示了类间关系,重点解析ArrayList、LinkedList、HashSet、HashMap等实现原理与性能特点,并指出线程安全及进阶特性,助你掌握集合体系关键知识点。
|
11月前
|
消息中间件 Cloud Native Java
SpringCloud概述
Spring Cloud是Spring推出的微服务一站式解决方案,弥补了分散技术栈的整合难题。它具备约定大于配置、组件丰富、开箱即用等特点,完美支持云原生架构。版本以伦敦地铁站命名,如Hoxton.SR12,避免与子项目版本冲突,便于统一管理。
SpringCloud概述
|
11月前
|
存储 关系型数据库 MySQL
为什么MySQL索引结构是B+tree ?
MySQL采用B+树作为索引结构,因其非叶子节点仅存键值与指针,可存储更多键,降低树高,提升查询效率。数据集中于叶子节点并形成双向链表,支持高效稳定的范围查询。通常树高为2-3层,即可容纳上千万数据,显著优于二叉树或B树。
|
11月前
|
数据库
什么是事务以及事务的四大特性?
事务是数据库操作的基本单位,具备ACID四大特性:原子性确保操作不可分割、全成功或全失败;一致性保证数据在事务前后保持正确状态;隔离性使事务独立运行,避免并发干扰;持久性指事务提交后更改永久生效。这些特性共同维护数据的完整性与可靠性。(238字)
|
11月前
|
算法 安全 数据安全/隐私保护
比较一下 DES、AES、SM4
DES、AES和SM4均为对称加密算法。DES采用56位密钥,已不推荐使用;AES支持128、192、256位密钥,全球广泛采用;SM4为我国商用密码标准,支持128位密钥,主要用于国内信息安全领域。
|
11月前
|
Java
synchronized 锁升级
synchronized锁有偏向锁、轻量级锁、重量级锁三级,性能依次降低。单线程用偏向锁;交替加锁无竞争升级为轻量级锁;存在竞争则升级为重量级锁。自Java 6支持锁升级,Java 15起偏向锁被废弃,因性能收益有限且可能负优化。
|
11月前
|
缓存 安全
String,StringBuilder 和 StringBuffer 的区别
String不可变,StringBuilder与StringBuffer可变;后者线程不安全,StringBuffer线程安全。大量拼接时优先选用后两者,多线程用StringBuffer,单线程用StringBuilder。String因final设计保证不可变,利于安全与缓存。

热门文章

最新文章