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. 启动shell时自动启动tmux

    Bash 对bash用户, 只需要将下面命令添加到自己家目录下的.bashrc, 要注意这句命令需要在alias配置之前.对其它shell的配置也是类似的 ~/.bashrc # If not run ...

  2. delphi实现两个目录路径的链接

    filepath := PathJoin(['C:', 'path1', 'path2\', 'a.doc']); // filepath = 'C:\path1\path2\a.doc' 代码: f ...

  3. SpringBoot application.yml logback.xml 多环境

    启动命令为 //开发环境 java -jar app.jar --spring.profiles.active=dev--server.port=8060 //测试环境 java -jar app.j ...

  4. Linux删除文件名中包含“-”的文件

    背景: 练习用shell的一些特殊符号,输出了一个 cat test.txt > -n,结果创建了一个叫做“-n”的文件   问题: 使用rm -f -n删除不了“-n"文件   解决 ...

  5. jdbcTemplate in

    参考 http://blog.csdn.net/gaopeng0071/article/details/75049952 使用NamedParameterJdbcTemplate public cla ...

  6. 神龟快跑,2016做的一款UWP游戏

    神龟快跑,2016做的一款UWP游戏, 实际是H5页面, 用LAYA转AS3得到的 安装地址 https://www.microsoft.com/zh-cn/store/p/神龟快跑/9nblggh4 ...

  7. Finding Hotels

    Finding Hotels http://acm.hdu.edu.cn/showproblem.php?pid=5992 Time Limit: 2000/1000 MS (Java/Others) ...

  8. MyBatis核心配置文件详解

    ------------------------siwuxie095                                     MyBatis 核心配置文件详解         1.核心 ...

  9. php反射机制学习

    PHP 5 具有完整的反射 API,可以通过反射机制来获取类,接口,函数的详细信息.例如可以通过反射api的成员属性,成员方法,命名空间的名称,检测某个类是否为抽象类等操作.(欢迎指点) 一般用途是在 ...

  10. URL去重

    import socket dictlist ={}; def ReadHost(): hosts = []; obn = open('d:/sss.txt', 'rb'); for line in ...