类型擦除

Java在语法中虽然存在泛型的概念,但是在虚拟机中却没有泛型的概念,虚拟机中所有的类型都是普通类。无论何时定义一个泛型类型,编译后类型会被都被自动转换成一个相应的原始类型。

比如这个类

public class Parent<T>
{
public void sayHello(T value)
{
System.out.println("This is Parent Class, value is " + value);
}
}

在编译后就变成了

public class Parent
{
public void sayHello(Object value)
{
System.out.println("This is Parent Class, value is " + value);
}
}

对类型变量进行替换的规则有两条:

  • 若为无限定的类型,如<T>,被替换为Object
  • 若为限定类型,如<T extends Comparable & Serializable>,则用第一个限定的类型变量来替换,在这里被替换为Comparable

桥方法

类型擦除后,就产生了一个奇怪的现象。

假设有一个超类:

public class Parent<T>
{
public void sayHello(T value)
{
System.out.println("This is Parent Class, value is " + value);
}
}

以及一个子类:

public class Child extends Parent<String>
{
public void sayHello(String value)
{
System.out.println("This is Child class, value is " + value);
}
}

最后有以下测试代码,企图实现多态:

public class MainApp
{
public static void main(String[] args)
{
Child child = new Child();
Parent<String> parent = child; parent.sayHello("This is a string");
}
}

运行的时候,会对Child类的方法表进行搜索,先分析一下Child类的方法表里有哪些东西:

1. sayHello(Object value) : 从类型被擦除后的超类中继承过来
2. sayHello(String value) : 自己新增的方法,和超类毫无联系
3. 一些从Object类继承来的方法,这里忽略

按理来说,这段测试代码应该不能通过编译,因为要实现多态的话,所调用的方法必须在子类中重写,但是在这里Child类并没有重写Parent类中的sayHello(Object value)方法,只是单纯的继承而已,并且新加了一个参数不同的同名方法。

但是结果是可以正常运行。

原因是编译器在Child类中自动生成了一个桥方法

public void sayHello(Object value)
{
sayHello((String) value);
}

可以看出,这个桥方法实际上就是对超类中sayHello(Obejct)的重写。这样做的原因是,当程序员在子类中写下以下这段代码的时候,本意是对超类中的同名方法进行重写,但因为超类发生了类型擦除,所以实际上并没有重写成功,因此加入了桥方法的机制来避免类型擦除与多态发生冲突。

public class Child extends Parent<String>
{
public void sayHello(String value)
{
System.out.println("This is Child class, value is " + value);
}
}

桥方法并不需要自己手动生成,一切都是编译器自动完成的。

桥方法与Geter

同样的,如果超类中有getter的话,在使用多态的时候也可能发生冲突。假设有超类被类型擦除后存在这样一个方法:

Obejct getValue()

然后在子类中,程序员想要重写这个方法,因此新增了一个这样的方法:

String getValue()

但是正如前面所述,重写并没有起作用,甚至还应该报错,因为在子类中,根据 函数签名=方法名+参数 的原则,从超类继承的方法与新增的方法冲突了。

但实际上这样的代码是可以工作的,原因在于,JVM是用返回值+方法名+参数的方式来计算函数签名的,所以编译器就可以借助这一原则来生成一个桥方法。不过这种计算函数签名的方法仅仅存在于虚拟机中。

Java中的类型擦除与桥方法的更多相关文章

  1. java 泛型的类型擦除与桥方法

    泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...

  2. java 泛型的类型擦除和桥方法

    oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html 在Java中,泛型的引入是为了在编译时提供强 ...

  3. Java中泛型 类型擦除

    转自:Java中泛型是类型擦除的 Java 泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,但有一点需要注意:Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类 ...

  4. Java泛型类与类型擦除

    转载自:http://blog.csdn.net/lonelyroamer/article/details/7868820 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型. ...

  5. c++中的类型擦除

    (原创)c++中的类型擦除 c++11 boost技术交流群:296561497,欢迎大家来交流技术. 关于类型擦除,可能很多人都不清楚,不知道类型擦除是干啥的,为什么需要类型擦除.有必要做个说明,类 ...

  6. Java泛型之类型擦除

    类型擦除 学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组.无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦): ...

  7. java中获取日期和时间的方法总结

    1.获取当前时间,和某个时间进行比较.此时主要拿long型的时间值. 方法如下:  要使用 java.util.Date .获取当前时间的代码如下 Date date = new Date(); da ...

  8. Java泛型:类型擦除

    类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...

  9. Java中double类型的数据精确到小数点后两位

    Java中double类型的数据精确到小数点后两位 多余位四舍五入,四种方法 一: double f = 111231.5585;BigDecimal b = new BigDecimal(f); d ...

随机推荐

  1. FileDetector-基于java开发的照片整理工具

    1. 项目背景 开发这个功能的主要原因如下: 1. 大学期间拍摄了约50G的照片,照片很多 2. 存放不规范,导致同一张照片出现在不同的文件夹内,可读性差,无法形成记忆线. 3. 重复存放过多,很多照 ...

  2. Codis分布式锁

    近期一项需求需要使用分布式锁,考虑的方案主要有如下两种: zookeeper codis 因为对于zookeeper不是特别熟悉,因此选用了codis,Codis是一个分布式的Redis解决方案,从应 ...

  3. Linq--一个集合中查找另一个集合,需熟悉这种写法

    //获取科室与病区授权的护士信息        public List<SYS_ZGKSBQDYK> GetUserWardMapByWardCode(string wardCode)   ...

  4. Servlet和JSP生命周期概述

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt374 Servlet生命周期分为三个阶段: 1,初始化阶段  调用init( ...

  5. Ljava.lang.Object;@ba8a1dc

    因为你从数据库读出数据后,存入到list集合上时,如果你没有指定要存入的数据的类型,系统会自动给你赋一个object类型,他是所以类的鼻祖,你取出数据要进行转型,转化成你自己想要的数据类型才能显示.它 ...

  6. 数据库学习任务四:数据读取器对象SqlDataReader、数据适配器对象SqlDataAdapter、数据集对象DataSet

    数据库应用程序的开发流程一般主要分为以下几个步骤: 创建数据库 使用Connection对象连接数据库 使用Command对象对数据源执行SQL命令并返回数据 使用DataReader和DataSet ...

  7. ★不容错过的PPT教程!

    IT工程师必须学会的计算机基础应用之一--PPT! 28项大神级PPT制作技术,学会后让你变成PPT高手哦!更多实用教程,请关注@IT工程师 !

  8. 如何将RDS的数据同步到本地自建数据库

    长期以来有很多的用户咨询如何将RDS的数据同步到本地的数据库环境中,本篇文章以在阿里云的ECS服务器为例来说明如何将RDS的数据同步到本地数据库中.RDS对外提供服务是一个DNS地址+端口3306,这 ...

  9. 201521123013 《Java程序设计》第11周学习总结

    1. 本章学习总结 2. 书面作业 Q1.1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchronized修饰方法实现互斥同步访问,还有什么办法实现互斥 ...

  10. 201521123087《java程序设计》第13周学习总结

    1. 本周学习总结 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 答: 往返行 ...