详解java 中泛型中的类型擦除和桥方法

所属分类: 软件编程 / java 阅读数: 22
收藏 0 赞 0 分享

在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数据类型的规则

这篇文章主要介绍了Java数据类型的规则的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Spring整合TimerTask实现定时任务调度

这篇文章主要介绍了Spring整合TimerTask实现定时任务调度的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

详解SpringMVC使用MultipartFile实现文件的上传

本篇文章主要介绍了SpringMVC使用MultipartFile实现文件的上传,本地的文件上传到资源服务器上,比较好的办法就是通过ftp上传。这里是结合SpringMVC+ftp的形式上传的,有兴趣的可以了解一下。
收藏 0 赞 0 分享

SpringMVC上传文件的三种实现方式

本篇文章主要介绍了SpringMVC上传文件的三种实现方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

微信公众帐号开发-自定义菜单的创建及菜单事件响应的实例

本篇文章主要介绍了微信公众帐号开发-自定义菜单的创建及菜单事件响应的实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
收藏 0 赞 0 分享

浅析Java中的继承与组合

本文将介绍组合和继承的概念及区别,并从多方面分析在写代码时如何进行选择。文中通过示例代码介绍的很详细,有需要的朋友可以参考借鉴,下面来一起看看吧。
收藏 0 赞 0 分享

利用反射获取Java类中的静态变量名及变量值的简单实例

下面小编就为大家带来一篇利用反射获取Java类中的静态变量名及变量值的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

java启动线程的3种方式对比分析

这篇文章主要为大家对比分析了java启动线程的3种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

SpringMVC上传和解析Excel方法

这篇文章主要介绍了SpringMVC上传和解析Excel方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

JAVA中String类与StringBuffer类的区别

这篇文章主要为大家详细介绍了JAVA中String类与StringBuffer类的区别,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享
查看更多