泛型中的类型擦除和桥方法
2015-12-10 11:16
417 查看
在Java中,泛型的引入是为了在编译时提供强类型检查和支持泛型编程。为了实现泛型,Java编译器应用类型擦除实现:
1、 用类型参数(type parameters)的限定(如果没有就用Object)替换泛型类型中的所有类型参数。
2、 需要保持类型安全的时候插入类型转换(隐含插入)
3、 在extened 泛型类型中生成桥方法来保证多态性
类型擦除确保不会为已参数化了的类型(paramterized types)产生新类,这样泛型能保证没有运行时的负载。
泛型类型擦除
在类型擦除过程中,java编译器擦除所有类型参数,用它的限定或者Object(没限定时)替换。
考虑下面的泛型类:
因为类型参数T是非限定的,Java编译器使用Object替换它:
下面的例子,泛型Node类使用了限定类型参数:
编译器会使用第一个限定类,Comparable替换限定参数类型T:
同样,泛型方法也可以擦除。规则类似,不细说。
类型擦除的影响和桥方法
有时候类型擦除会引起无法预知的情况。比如:
给定以下两个类:
类型擦除后,代码变成:
类型擦除后,方法的签名已经不匹配。Node 方法变成setData(Object),MyNode方法变成setData(Integer)。MyNode setData方法已经不是覆盖Node setData方法。
为了解决这个问题,维持泛型类型的多态性,java编译器会生成一个桥方法:
原文:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
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); } // ... }
原文:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
相关文章推荐
- 表格,合并单元格colspan,rowspan
- java文件copy,fileutils工具包和缓存流
- nodejs-模块
- 排序算法之快速排序
- Mac 应用开发 window 显示的样式
- xampp apache port 更改
- ubuntu报错: the‘webob>=1.2’distribution was not found
- 【SSH项目实战】国税协同平台-33.quartz&SimpleTrigge
- 【SSH项目实战】国税协同平台-34.quartz&CronTrigger
- iOS开发经验积累 二
- JPA注解说明
- php apc
- DB2常用函数详解(一):字符串函数
- .tar.bz2文件解压命令
- SDK目录结构
- Android开发中优秀的app 异常处理机制
- 10008---MySql 数据导入导出
- python configParser 模板
- Eclipse中安装Genymotion插件
- QT Creator安装版跟进 QT源码笔记