类型擦除
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中的类型擦除与桥方法的更多相关文章
-
java 泛型的类型擦除与桥方法
泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...
-
java 泛型的类型擦除和桥方法
oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html 在Java中,泛型的引入是为了在编译时提供强 ...
-
Java中泛型 类型擦除
转自:Java中泛型是类型擦除的 Java 泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,但有一点需要注意:Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类 ...
-
Java泛型类与类型擦除
转载自:http://blog.csdn.net/lonelyroamer/article/details/7868820 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型. ...
-
c++中的类型擦除
(原创)c++中的类型擦除 c++11 boost技术交流群:296561497,欢迎大家来交流技术. 关于类型擦除,可能很多人都不清楚,不知道类型擦除是干啥的,为什么需要类型擦除.有必要做个说明,类 ...
-
Java泛型之类型擦除
类型擦除 学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组.无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦): ...
-
java中获取日期和时间的方法总结
1.获取当前时间,和某个时间进行比较.此时主要拿long型的时间值. 方法如下: 要使用 java.util.Date .获取当前时间的代码如下 Date date = new Date(); da ...
-
Java泛型:类型擦除
类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...
-
Java中double类型的数据精确到小数点后两位
Java中double类型的数据精确到小数点后两位 多余位四舍五入,四种方法 一: double f = 111231.5585;BigDecimal b = new BigDecimal(f); d ...
随机推荐
-
Objective-C Mojo和Django 对接
最近在做资料类app需要一个好的资源管理工具,excel在这方面非常好,不过能第一非常low,第二数据量一大查询就是个问题. 因此,我使用django做了个资源管理小工具.好处还是很明显的 (1)可以 ...
-
OC中的字典
// ********************不可变最字典***************** /* NSDictionary * dic = [NSDictionary dictionaryWithO ...
-
nginx(1、正向代理)
正向代理是指客户端通过代理服务器访问某一个服务器,最常见的例子是内网用户通过代理访问外网,以及所谓的“FQ”. 在windows下实例如下: 1.下载安装包:nginx-1.7.9.zip: 2.解压 ...
-
Linux系统管理命令之用户管理
1.添加用户useradd 2.删除用户userdel userdel aming 彻底删除用户(包括删除用户目录) userdel -r aming 3.用户修改usermod
-
Redis-秒杀场景应用
Redis Util实现 package test.jedis; import java.util.List; import java.util.Set; import redis.clients.j ...
-
Microsoft Office 2007的ContentType
当从浏览器返回一个文件时,需要指定ContentType,以下是Office2007对应的值: "application/vnd.openxmlformats-officedocument. ...
-
【JavaScript】一些注意点
1.var与没有var的区别 没 2.全局变量和局部变量的速度 3.函数内部的var和外部的var的区别 4.var m =new Array();与var m = [];区别
-
一个action读取另一个action里的session
action 1: private Map session; session.put("projectname_session", request1.getParameter(&q ...
-
Centos7 编译安装 Nginx PHP Mariadb Memcached 扩展 ZendOpcache扩展 (实测 笔记 Centos 7.3 + Openssl 1.1.0e + Mariadb 10.1.22 + Nginx 1.12.0 + PHP 7.1.4 + Laravel 5.4 )
环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7-x86_64-Minimal-1611.iso 安装步骤: 1.准备 1.0 查看硬 ...
-
【Spring】6、注解大全
一.@interface Java用 @interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类. 二.@Override,@Deprecated,@S ...