Java泛型的类型擦除示例详解

 更新时间:2021年07月29日 12:45:06   作者:宿宝臣  
Java泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,但有一点需要注意,Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类型在编译后都会被清除掉,这篇文章主要给大家介绍了关于Java泛型的类型擦除的相关资料,需要的朋友可以参考下

前言

Java泛型这个特性是从JDK 1.5才开始加入的,因此为了兼容之前的版本,Java泛型的实现采取了“伪泛型”的策略,即Java在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样。理解类型擦除对于用好泛型是很有帮助的,尤其是一些看起来“疑难杂症”的问题,弄明白了类型擦除也就迎刃而解了。

泛型的类型擦除原则是:

•消除类型参数声明,即删除<>及其包围的部分。

•根据类型参数的上下界推断并替换所有的类型参数为原生态类型:如果类型参数是无限制通配符或没有上下界限定则替换为Object,如果存在上下界限定则根据子类替换原则取类型参数的最左边限定类型(即父类)。

•为了保证类型安全,必要时插入强制类型转换代码。

•自动产生“桥接方法”以保证擦除类型后的代码仍然具有泛型的“多态性”。

1 擦除类定义中的类型参数

1.1 无限制类型擦除

当类定义中的类型参数没有任何限制时,在类型擦除中直接被替换为Object,即形如<T>和<?>的类型参数都被替换为Object,参见1。

图 1: 擦除类定义中的类型参数

1.2 有限制类型擦除

当类定义中的类型参数存在限制(上下界)时,在类型擦除中替换为类型参数的上界或者下界,比如形如<T extends Number>和<? extends Number>的类型参数被替换为Number,<? super Number>被替换为Object,参见2。

图 2: 擦除类定义中的有限制类型参数

2 擦除方法定义中的类型参数

擦除方法定义中的类型参数原则和擦除类定义中的类型参数是一样的,这里仅以擦除方法定义中的有限制类型参数为例,见3。

图 3: 擦除泛型方法中的类型参数

3 桥接方法和泛型的多态

考虑下面的代码:

public interface Info&lt;T&gt; {
    // just return var:-) 
    T info(T var); 
}
public class BridgeMethodTest implements Info&lt;Integer&gt; {
    @Override
    public Integer info(Integer var) {
        return var;
    }
}

按照我们之前类型擦除的经验,在擦除类型后的代码应该是这个样子的:

public interface Info {
    // just return var
    Object info(Object var);
}

public class BridgeMethodTest implements Info {
    @Override
    public Integer info(Integer var) {
        return var;
    }
}

但是,明显可以看出,这样擦除类型后的代码在语法上是错误的:BridgeMethodTest类中虽然存在一个info方法,但是和Info接口要求覆盖的info方法不一致:参数类型不一致。在这种情况下,Java编译器会自动增加一个所谓的“桥接方法”(bridge method)来满足Java语法的要求,同时也保证了基于泛型的多态能够有效。我们反编译一下BridgeMethodTest.class文件可以看到Java编译器到底是如何做的:

$ javap BridgeMethodTest.class 

Compiled from “BridgeMethodTest.java”

public class BridgeMethodTest implements Info<java.lang.Integer> {

public BridgeMethodTest();

public java.lang.Integer info(java.lang.Integer);

public java.lang.Object info(java.lang.Object);

}

可以看出,Java编译器在BridgeMethodTest中自动增加了两个方法:默认构造方法和参数为Object的info方法,参数为Object的info方法就是“桥接方法”。如何理解“桥接”二字呢?我们进一步反编译BridgeMethodTest看一下:

// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.                                                          
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   BridgeMethodTest.java
 
 
public class BridgeMethodTest
    implements Info
{
 
    public BridgeMethodTest()
    {   
    }   
 
    public Integer info(Integer integer)
    {   
        return integer;
    }   
 
    public volatile Object info(Object obj)
    {   
        return info((Integer)obj);
    }   
}

info(Object)方法通过调用子类的info(Integer)方法搭起了父类和子类的桥梁,也就是说,info(Object obj)这个方法起到了连接父类和子类的作用,使得Java的多态在泛型情况下依然有效。

当然,我们在使用基于泛型的多态时不必过多的考虑“桥接方法”,Java编译器会帮我们打理好一切。

关于桥接方法的更多信息可以参考:JLS的相关章节。

总结

到此这篇关于Java泛型类型擦除的文章就介绍到这了,更多相关Java泛型类型擦除内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

参考资料

•http://docs.oracle.com/javase/tutorial/java/generics/index.html

•http://docs.oracle.com/javase/tutorial/extra/generics/index.html

相关文章

  • Java数据库连接池之DBCP浅析_动力节点Java学院整理

    Java数据库连接池之DBCP浅析_动力节点Java学院整理

    这篇文章主要为大家详细介绍了Java数据库连接池之DBCP的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • Java 数据结构与算法系列精讲之哈希算法实现

    Java 数据结构与算法系列精讲之哈希算法实现

    哈希表本质是一种(key,value)结构,由此我们可以联想到,能不能把哈希表的key映射成数组的索引index呢?如果这样做的话那么查询相当于直接查询索引,查询时间复杂度为O(1),其实这也正是当key为int型时的做法,将key通过某种做法映射成index,从而转换成数组结构
    2022-02-02
  • 多层嵌套的json的值如何解析/替换

    多层嵌套的json的值如何解析/替换

    这篇文章主要介绍了多层嵌套的json的值如何解析/替换的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • springboot Junit 执行顺序详解

    springboot Junit 执行顺序详解

    这篇文章主要介绍了springboot Junit 执行顺序,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Java项目打包Docker镜像全流程

    Java项目打包Docker镜像全流程

    本文是一份超详细的Java项目Docker化实战手册,从环境准备到最终上线,手把手带你完成整个容器化部署流程,无论你是刚接触Docker的新手,还是想系统梳理容器化流程的开发者,这篇文章都能给你带来实实在在的帮助,需要的朋友可以参考下
    2025-04-04
  • Springboot Retry组件@Recover失效问题解决方法

    Springboot Retry组件@Recover失效问题解决方法

    在使用springboot的retry模块时,你是否出现过@Recover注解失效的问题呢?不用担心,这篇文章就来告诉你解决@Recover失效的办法,需要的小伙伴可以参考一下
    2021-11-11
  • OGNL表达式基本语法与用法详解

    OGNL表达式基本语法与用法详解

    这篇文章主要介绍了OGNL表达式基本语法与用法详解,具有一定参考价值。需要的朋友可以了解下。
    2017-09-09
  • IntelliJ IDEA失焦自动重启服务的解决方法

    IntelliJ IDEA失焦自动重启服务的解决方法

    在使用 IntelliJ IDEA运行 SpringBoot 项目时,你可能会遇到一个令人困扰的问题,一旦你的鼠标指针离开当前IDE窗口,点击其他位置时, IDE 窗口会失去焦点,你的 SpringBoot 服务就会自动重启,所以本文给大家介绍了IntelliJ IDEA失焦自动重启服务的解决方法
    2023-10-10
  • Spring Boot应用关闭分析详解

    Spring Boot应用关闭分析详解

    本文挖掘了Spring Boot的关闭方式,并列举了关闭方式,从原理、源码的角度阐述了Spring Boot的关闭代码及扩展点,感兴趣的朋友一起看看吧
    2024-12-12
  • 一篇文章带你入门java多线程

    一篇文章带你入门java多线程

    这篇文章主要介绍了java多线程编程实例,分享了几则多线程的实例代码,具有一定参考价值,加深多线程编程的理解还是很有帮助的,需要的朋友可以参考下
    2021-08-08

最新评论