The Java™ Tutorials — Generics :Effects of Type Erasure and Bridge Methods 类型擦除的影响以及桥方法

The Java™ Tutorials — Generics :Effects of Type Erasure and Bridge Methods 类型擦除的影响以及桥方法

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

关键点

  • 补充阅读:http://www.cnblogs.com/ggjucheng/p/3352519.html
  • 桥方法的功能:防止类型擦除后子类无法override父类的方法,保护泛型的多态性

全文翻译

Sometimes type erasure causes a situation that you may not have anticipated. The following example shows how this can occur. The example (described in Bridge Methods) shows how a compiler sometimes creates a synthetic method, called a bridge method, as part of the type erasure process.

有些时候类型擦除会引起一个你可能意想不到的情况。下面这个例子就展示了这是如何发生的。本例(通过桥方法展示)展示了编译器是如何在某些情况下创建合成方法的。这个合成方法就是所谓的“桥方法”,它是整个类型擦除过程中的一部分。

Given the following two classes:

下面给出两个类:

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

Consider the following code:

再看下下面的两段代码:

MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = mn.data; // Causes a ClassCastException to be thrown.

After type erasure, this code becomes:

在类型擦除后,代码变成了:

MyNode mn = new MyNode(5);
Node n = (MyNode)mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = (String)mn.data; // Causes a ClassCastException to be thrown.

Here is what happens as the code is executed:

  • n.setData(“Hello”); causes the method setData(Object) to be executed on the object of class MyNode. (The MyNode class inherited setData(Object) from Node.)
  • In the body of setData(Object), the data field of the object referenced by n is assigned to a String.
  • The data field of that same object, referenced via mn, can be accessed and is expected to be an integer (since mn is a MyNode which is a Node<Integer>.
  • Trying to assign a String to an Integer causes a ClassCastException from a cast inserted at the assignment by a Java compiler.

下面就是代码的执行过程:

  • n.setData(“Hello”)触发了在MyNode类实例对象上setData(Object)方法的执行。(MyNode类从Node类中继承到了setData(Object)方法)
  • 在setData(Object)方法体中,变量n所引用的对象的数据域被赋值为一个String。
  • 通过mn变量引用的同一个对象的数据域对外可见,并且期望的类型为Integer(因为MyNode就是一个Node<Integer>类型)
  • 尝试把一个String赋值给一个Integer时,就会在类型转换的过程引起ClassCastException异常。这个类型转换过程是由编译器在赋值时插入的。

Bridge Methods 桥方法

When compiling a class or interface that extends a parameterized class or implements a parameterized interface, the compiler may need to create a synthetic method, called a bridge method, as part of the type erasure process. You normally don’t need to worry about bridge methods, but you might be puzzled if one appears in a stack trace.

当编译一个扩展参数化类的类,或一个实现了参数化接口的接口时,编译器有可能因此要创建一个合成方法,名为桥方法。它是类型擦除过程中的一部分。一般情况下你无须为桥方法费心,但是当它出现在栈追踪信息里时,你可能会对它感到疑惑。

After type erasure, the Node and MyNode classes become:

在类型擦除后,Node和MyNode类就变成了这样:

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

After type erasure, the method signatures do not match. The Node method becomes setData(Object) and the MyNode method becomes setData(Integer). Therefore, the MyNode setData method does not override the Node setData method.

在类型擦除后,两个方法的签名并不相同。Node类的这个方法成为了setData(Object),并且MyNode的这个方法就成为了setData(Integer)。因此,MyNode的setData方法并没有重写Node的setData方法。

To solve this problem and preserve the polymorphism of generic types after type erasure, a Java compiler generates a bridge method to ensure that subtyping works as expected. For the MyNode class, the compiler generates the following bridge method for setData:

为了解决这个问题并保持类型擦除后泛型的多态性,编译器生成了一个桥方法以保证子类按照预期工作。对于MyNode类,编译器为setData()生成了桥方法:

class MyNode extends Node {

// Bridge method generated by the compiler
//
public void setData(Object data) {
setData((Integer) data);
}

public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}

// ...
}

As you can see, the bridge method, which has the same method signature as the Node class’s setData method after type erasure, delegates to the original setData method.

正如你所见,桥方法和类型擦除后Node中的setData方法有着同样签名。而这个桥方法也被分配到了原来setData方法中。

你可能感兴趣的:(java,泛型,type,类型擦除,erasure,桥方法)