The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
Sometimes type erasure causes a situation that you may not have anticipated. 有时,类型擦除会导致您可能没有预料到的情况。The following example shows how this can occur. 下面的示例显示了这是如何发生的。The following example shows how a compiler sometimes creates a synthetic method, which is 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"); // Causes a ClassCastException to be thrown. Integer x = mn.data;
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"); // Causes a ClassCastException to be thrown. Integer x = (String)mn.data;
The next section explains why a 下一节将解释为什么在ClassCastException
is thrown at the n.setData("Hello");
statement.n.setData("Hello");
语句上抛出ClassCastException
。
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, which is 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.setData(T) method becomes Node.setData(Object). 类型擦除后,方法签名不匹配;Node.setData(T)方法变为Node.setData(Object)。As a result, the MyNode.setData(Integer) method does not override the Node.setData(Object) method.因此,MyNode.setData(Integer)方法不会覆盖Node.setData(Object)方法。
To solve this problem and preserve the polymorphism of generic types after type erasure, the Java compiler generates a bridge method to ensure that subtyping works as expected.为了解决这个问题并在类型删除后保留泛型类型的多态性,Java编译器生成一个桥接方法以确保子类型按预期工作。
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); } // ... }
The bridge method 桥接方法MyNode.setData(object)
delegates to the original MyNode.setData(Integer)
method. MyNode.setData(object)
委托给原始的MyNode.setData(Integer)
方法。As a result, the 因此,n.setData("Hello");
statement calls the method MyNode.setData(Object)
, and a ClassCastException
is thrown because "Hello"
can't be cast to Integer
.n.setData("Hello");
语句调用方法MyNode.setData(Object)
,并引发ClassCastException
,因为"Hello"
不能转换为Integer
。