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

网友投稿 251 2023-05-06


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

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

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

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

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

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

泛型类型擦除

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

考虑下面的泛型类:

public class Node {

private T data;

private Node next;

public Node(T data, Node 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> {

private T data;

private Node next;

public Node(T data, Node 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 {

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 {

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; // 原生类型 – http://编译器会给出未检查警告

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);

}

// ...

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解Angular2组件之间如何通信
下一篇:微信小程序图片宽100%显示并且不变形
相关文章

 发表评论

暂时没有评论,来抢沙发吧~