java 泛型的类型擦除和桥方法

java

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

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

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

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

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

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

泛型类型擦除

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

     考虑下面的泛型类:  

 1 public class Node<T> {

2

3 private T data;

4 private Node<T> next;

5

6 public Node(T data, Node<T> next) }

7 this.data = data;

8 this.next = next;

9 }

10

11 public T getData() { return data; }

12 // ...

13 }

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

 1  public class Node {

2

3 private Object data;

4 private Node next;

5

6 public Node(Object data, Node next) {

7 this.data = data;

8 this.next = next;

9 }

10

11 public Object getData() { return data; }

12 // ...

13 }

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

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

2

3 private T data;

4 private Node<T> next;

5

6 public Node(T data, Node<T> next) {

7 this.data = data;

8 this.next = next;

9 }

10

11 public T getData() { return data; }

12 // ...

13 }

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

 1 public class Node {

2

3 private Comparable data;

4 private Node next;

5

6 public Node(Comparable data, Node next) {

7 this.data = data;

8 this.next = next;

9 }

10

11 public Comparable getData() { return data; }

12 // ...

13 }

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

类型擦除的影响和桥方法

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

给定以下两个类:

 1 public class Node<T> {

2

3 public T data;

4

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

6

7 public void setData(T data) {

8 System.out.println("Node.setData");

9 this.data = data;

10 }

11 }

12

13 public class MyNode extends Node<Integer> {

14 public MyNode(Integer data) { super(data); }

15

16 public void setData(Integer data) {

17 System.out.println("MyNode.setData");

18 super.setData(data);

19 }

20 }

考虑以下代码: 

1  MyNode mn = new MyNode(5);

2 Node n = mn; // 原生类型 – 编译器会给出未检查警告

3 n.setData("Hello");

4 Integer x = mn.data; // 会引发抛出ClassCastException

类型擦出后,代码变成

1 MyNode mn = new MyNode(5);

2 Node n = (MyNode)mn; //原生类型 – 编译器会给出未检查警告

3 n.setData("Hello");

4 Integer x = (String)mn.data; //会引发抛出ClassCastException

 1 public class Node {

2

3 public Object data;

4

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

6

7 public void setData(Object data) {

8 System.out.println("Node.setData");

9 this.data = data;

10 }

11 }

12

13 public class MyNode extends Node {

14

15 public MyNode(Integer data) { super(data); }

16

17 public void setData(Integer data) {

18 System.out.println("MyNode.setData");

19 super.setData(data);

20 }

21 }

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

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

 1 class MyNode extends Node {

2

3 // 编译器生成的桥方法

4 //

5 public void setData(Object data) {

6 setData((Integer) data);

7 }

8

9 public void setData(Integer data) {

10 System.out.println("MyNode.setData");

11 super.setData(data);

12 }

13

14 // ...

15 }

以上是 java 泛型的类型擦除和桥方法 的全部内容, 来源链接: utcz.com/z/392324.html

回到顶部