oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

在Java中,泛型的引入是为了在编译时提供强类型检查和支持泛型编程。为了实现泛型,Java编译器应用类型擦除实现:

1、  用类型参数(type parameters)的限定(如果没有就用Object)替换泛型类型中的所有类型参数。

2、  需要保持类型安全的时候插入类型转换(隐含插入)

3、  在extened 泛型类型中生成桥方法来保证多态性

类型擦除确保不会为已参数化了的类型(paramterized types)产生新类,这样泛型能保证没有运行时的负载。

泛型类型擦除

在类型擦除过程中,java编译器擦除所有类型参数,用它的限定或者Object(没限定时)替换。

考虑下面的泛型类:  

 public class Node<T> {

     private T data;
private Node<T> next; public Node(T data, Node<T> next) }
this.data = data;
this.next = next;
} public T getData() { return data; }
// ...
}

因为类型参数T是非限定的,Java编译器使用Object替换它:  

  public class Node {

     private Object data;
private Node next; public Node(Object data, Node next) {
this.data = data;
this.next = next;
} public Object getData() { return data; }
// ...
}

下面的例子,泛型Node类使用了限定类型参数:

  public class Node<T extends Comparable<T>> {

     private T data;
private Node<T> next; public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
} public T getData() { return data; }
// ...
}

编译器会使用第一个限定类,Comparable替换限定参数类型T:

 public class Node {

     private Comparable data;
private Node next; public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
} public Comparable getData() { return data; }
// ...
}

同样,泛型方法也可以擦除。规则类似,不细说。

类型擦除的影响和桥方法

有时候类型擦除会引起无法预知的情况。比如:

给定以下两个类:

 public class Node<T> {

     public T data;

     public Node(T data) { this.data = data; }

     public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
} public class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); } public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}

考虑以下代码:

  MyNode mn = new MyNode(5);
Node n = mn; // 原生类型 – 编译器会给出未检查警告
n.setData("Hello");
Integer x = mn.data; // 会引发抛出ClassCastException

类型擦出后,代码变成

 MyNode mn = new MyNode(5);
Node n = (MyNode)mn; //原生类型 – 编译器会给出未检查警告
n.setData("Hello");
Integer x = (String)mn.data; //会引发抛出ClassCastException
 public class Node {

     public Object data;

     public Node(Object data) { this.data = data; }

     public void setData(Object data) {
System.out.println("Node.setData");
this.data = data;
}
} public class MyNode extends Node { public MyNode(Integer data) { super(data); } public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}

类型擦除后,方法的签名已经不匹配。Node 方法变成setData(Object),MyNode方法变成setData(Integer)。MyNode setData方法已经不是覆盖Node setData方法。

为了解决这个问题,维持泛型类型的多态性,java编译器会生成一个桥方法:

 class MyNode extends Node {

     // 编译器生成的桥方法
//
public void setData(Object data) {
setData((Integer) data);
} public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
} // ...
}

java 泛型的类型擦除和桥方法的更多相关文章

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

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

  2. Java中的类型擦除与桥方法

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

  3. Java泛型:类型擦除

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

  4. Java泛型之类型擦除

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

  5. Java泛型-类型擦除

    一.概述 Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变 ...

  6. 转:有关Java泛型的类型擦除(type erasing)

    转载自:拈花微笑 自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资.在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结 ...

  7. JAVA 泛型之类型擦除

    ★ 泛型是 JDK 1.5 版本引进的概念,之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容. CollectionTest.java ---编译成CollectionTest. ...

  8. Java泛型的类型擦除

    package com.srie.testjava; import java.util.ArrayList; import java.util.List; public class TestGener ...

  9. Java泛型类与类型擦除

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

随机推荐

  1. 迷你MVVM框架 avalonjs 1.4.1发布

    以后有关avalon的版本升级消息,全部改放到这里 重构parseHTML,让其支持xhtml 强化 ms-duplex-number拦截器 添加data-duplex-number辅助指令 值为st ...

  2. Delphi编程实现是否开启“平滑屏幕字体边缘“

    在Windows高级设置中的视觉效果中可以设置是否开启“平滑屏幕字休边缘”,可以通过编程的方式来实现: if SystemParametersInfo(SPI_SETFONTSMOOTHING, 1, ...

  3. 【Java】JVM(五)、虚拟机类加载机制

    一.概念 类加载:虚拟机把类的数据从Class文件加载到内存中,并对数据进行校验,转化解析,和初始化,最终形成可以被虚拟机直接使用的Java类型. 二.加载时机 1.加载 加载阶段虚拟机完成的工作为: ...

  4. mysql连接数据库存报下面错误:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

    输入 mysql -u root 登录 mysql 的时候出现以下错误: ERROR 2002 (HY000): Can't connect to local MySQL server through ...

  5. client / server端用户的登录

    # 客户端 import socket import hashlib import json import os import struct sk = socket.socket() # 实例化 sk ...

  6. 57. Insert Interval (Array; Sort)

    Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...

  7. 常用特殊符号的HTML代码(HTML字符实体)

    适当使用实体,对页面开发有相当大的帮助. 自己收集的一些常用的以实体代替与HTML语法相同的字符,避免浏览解析错误. 常用HTML字符实体(建议使用实体): 字符 名称 实体名 实体数 • 圆点   ...

  8. 21-js 实现评论时间格式转化

    js里面要用可以用伊尔表达式,循环是用js: document.getElementById("${pj.pltime }").innerHTML = dateToGMT(&quo ...

  9. php中正则案例分析

    案例一如下: $regex='/[\s\S]*/'; $str='lemon'; $matches=array(); if(preg_match($regex,$str,$matches)){ var ...

  10. 如何利用jQuery post传递含特殊字符的数据【转】

    在jQuery中,我们通常利用$.ajax或$.post进行数据传递处理,但这里通常不能传递特殊字符,如:“<”.本文就介绍如何传递这种含特殊字符的数据. 1.准备页面和控制端代码 页面代码如下 ...