Java 泛型 泛型代码和虚拟机

时间:2022-09-21 21:52:06

Java 泛型 泛型代码和虚拟机

@author ixenos

类型擦除、原始类型、给JVM的指令、桥方法、Java泛型转换的事实

类型擦除(type erasure)

n  Java泛型的处理在编译器中运行,编译生成的字节码bytecode不包含泛型信息,泛型信息在编译处理时被擦除(erasure),这个过程即类型擦除

原始类型(raw type)

n  定义一个泛型类型,编译器自动提供一个相应的原始类型(raw type),原始类型就是删除类型参数(包括泛型类型变量及其限定类型)后的泛型类型名。擦除类型变量,原始类型替换为限定类型(无限定则用Object)

n  泛型变量有限定类型示例: <T extends Comparable & Serializable> ,因为Comparable包含实现方法CompareTo,而Serializable只是个标签(Tagging)接口,若二者对调位置,则原始类型将用Serializable来替换,这样在编译器必要时要向Comparable插入强制类型转换,所以为了提高效率,最好将标签(Tagging)接口放在边界列表的末尾

u  标签(Tagging)接口:没有方法的接口

给JVM的指令:擦除方法返回类型,编译器将方法调用处理为两条JVM虚拟机指令

n  对原始方法的调用(返回Object类型或限定类型)

n  将返回的Object类型强制转换为泛型类型的具体类型(如Employee)

u  补充#当存取一个泛型域时也要插入强制类型转换

桥方法(bridge method)

n  擦除前

Class DateInterval extends Pair

{

Public void setSecond(Date second)

{

If(…)

Super.setSecond(second);

}

}

n  擦除后

Class DateInterval extends Pair

{

Public void setSecond(Date second){…}

}

而这时候还出现了另一个从Pair继承的setSecond方法,形参是Object类型 : public void setSecond(Object second){…}

n  然后考虑下面的语句(要求多态调用)出现的问题:

DateInterval interval = new DateInterval(…);

Pairpair = interval;   //向上转型(assignment to superclass)

pair.setSecond(aDate);

u  问题一:类型擦除和多态冲突

向上转型后pair的setSecond方法可以多态调用了(即调用父类或子类的方法,一般调用子类方法),但是类型擦除后只能调用原始类型的方法。

问题一解决方案:编译器在DateInterval类中生成一个桥方法:

public void setSecond(Object second) {setSecond((Date) second)}

1、         当用pair.setSecond(aDate)调用方法时,将会调用DateInterval.setSecond(Object)方法(桥方法

2、         DateInterval.setSecond(Object)将调用DateInterval.setSecond(Date)方法

u  问题二:子类重写无参(方法签名相同)方法,但类中却出现两个返回类型不同(JDK 5允许重写时修改返回类型)的方法,(桥方法出现)

    {

    协变式覆盖(Override):http://www.cnblogs.com/ixenos/p/5645741.html

    在JDK 1.4及以前,子类方法如果要覆盖超类的某个方法,必须具有完全相同的方法签名,包括返回值也必须完全一样。

    JDK 5开始,只要子类方法与超类方法具有相同的方法签名(形参),或者子类方法的返回值是超类方法的子类型(增加了对协变返回值的支持),就可以覆盖

    }

   而返回类型的不同不算多态(重载),是JDK 5 开始有的合法重写(如上所述),所以一个类中出现两个仅有返回类型不同的方法在Java语言中是非法的,通不过编译。

假设DateInterval方法也覆盖了getSecond方法(仅改变返回类型):

Class DateInterval extends Pair

{

Public Date getSecond()

{

return (Date)super.getSecond().clone();

}

}

我们知道,返回类型的不同不算多态(重载),是重写,所以在一个类中出现两个仅有返回类型不同的方法在Java语言中是非法的,通不过编译。

然而,在擦除的类型中,即在DateInterval类中出现了两个getSecond方法():

Date getSecond() //在DateInterval中定义

Object getSecond() //桥方法!重写定义在Pair类中的方法,将会调用上面的方法Date getSecond()

#而在JVM虚拟机中是用返回值参数类型确定同一个方法的,因此如果编译器产生两个仅有返回类型不同的方法字节码,虚拟机能够正确地处理这一情况。

Java泛型转换的事实

n  虚拟机中没有泛型,只有普通的类和方法

n  所有的类型参数都用他们的限定类型替换

n  桥方法被合成来保持多态

n  为保持类型安全性,必要时插入强制类型转换

Java 泛型 泛型代码和虚拟机的更多相关文章

  1. Java泛型解析&lpar;03&rpar;:虚拟机运行泛型代码

    Java泛型解析(03):虚拟机运行泛型代码      Java虚拟机是不存在泛型类型对象的,全部的对象都属于普通类,甚至在泛型实现的早起版本号中,可以将使用泛型的程序编译为在1.0虚拟机上可以执行的 ...

  2. &lbrack;改善Java代码&rsqb;Java的泛型是类型擦除的

    泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generi ...

  3. Java高质量代码之 — 泛型与反射

    在Java5后推出了泛型,使我们在编译期间操作集合或类时更加的安全,更方便代码的阅读,而让身为编译性语言的Java提供动态性的反射技术,更是在框架开发中大行其道,从而让Java活起来,下面看一下在使用 ...

  4. Java&OpenCurlyDoubleQuote;禁止”泛型数组

    Java“禁止”泛型数组 原文:https://blog.csdn.net/yi_Afly/article/details/52058708 1. 泛型定义泛型编程是一种通过参数化的方式将数据处理与数 ...

  5. Java核心技术-泛型程序设计

    使用泛型机制编写的代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性. 泛型对于集合类尤其有用 1 为什么要使用泛型程序设计 泛型程序设计意味着编写的代码可以 ...

  6. 0072 Java中的泛型--泛型是什么--泛型类--泛型方法--擦除--桥方法

    什么是泛型,有什么用? 先运行下面的代码: public class Test { public static void main(String[] args) { Comparable c=new ...

  7. C&plus;&plus; Java C&num;泛型

    泛型概述C#中的泛型C#泛型和java泛型的比较C#泛型和C++模板的比较C#泛型中的约束 泛型概述 Bruce Eckel :您能对泛型做一个快速的介绍么? Anders Hejlsberg : 泛 ...

  8. Java的泛型详解&lpar;一&rpar;

    Java的泛型详解 泛型的好处 编写的代码可以被不同类型的对象所重用. 因为上面的一个优点,泛型也可以减少代码的编写. 泛型的使用 简单泛型类 public class Pair<T> { ...

  9. Java 中泛型的实现原理

    泛型是 Java 开发中常用的技术,了解泛型的几种形式和实现泛型的基本原理,有助于写出更优质的代码.本文总结了 Java 泛型的三种形式以及泛型实现原理. 泛型 泛型的本质是对类型进行参数化,在代码逻 ...

随机推荐

  1. 检测当前运行环境——移动端与PC端。

    方法1: $(function checkBrowser(){ var browser={ versions:function(){ var u = navigator.userAgent, app ...

  2. 获取某地的经纬度 &amp&semi;&amp&semi; 通过经纬度获取相应的地理位置

    最近要通过一个经纬度判断该经纬度是否位于某个地区内,所以通过网上查找资料,整合后出了下面的内容. 1.通过地址获取改地址的经纬度 /** * @param addr * 查询的地址 * @return ...

  3. 查询DBlink创建

    DBlink创建 查询 博客分类: Oracle   当用户要跨本地数据库,访问另外一个数据库表中的数据时,本地数据库中必须创建了远程数据库的dblink,通过dblink本地数据库可以像访问本地数据 ...

  4. main方法和args参数

    第一次接触java常常奇怪main方法和其参数有什么用.我们只知道main方法是程序入口,其实main方法同时也是一个可以手动调用的静态方法. 我们可以利用main方法写简单的一个递归程序 publi ...

  5. 最全的MonkeyRunner自动化测试从入门到精通(6)

    eclipse中进行插入PyDev插件的使用步骤一:monkeyrunner环境变量的配置.在Android Sdk中的tools目录下,拷贝路径,进行配置环境变量.与上面的配置方法一样,在这里不做过 ...

  6. Python 关于时间和日期函数使用 -- &lpar;转&rpar;

    python中关于时间和日期函数有time和datatime   1.获取当前时间的两种方法: import datetime,time now = time.strftime("%Y-%m ...

  7. 一个由有符号下标引起的bug

    先看段代码: if(s[d[i]]) { ... } 这里的d是一个char*的内存buffer,s是一个256长度的bool数组.上段代码逻辑是,s已进行过初始化,其作用是过滤字节,有些字节对应tr ...

  8. MySQL 事物和数据库锁

    1.数据库事物 1. 什么是事务  事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一 ...

  9. iptables和DNS

    1.iptables防火墙 表→链→规则 filter表 数据过滤表 NAT表---内网和外网的地址转换 Mangle-----数据流量,通过防火墙设置流量.特殊数据包标记.太复杂,一般不用.限速工具 ...

  10. ssm使用velocity模板语言

    1.在pom.xml里添加velocity模板语言支持的依赖 <!-- velocity模板语言支持包 --> <dependency> <groupId>org. ...