Documentation

The Java™ Tutorials
Hide TOC
Effects of Type Erasure and Bridge Methods类型擦除和桥接方法的影响
Trail: Learning the Java Language
Lesson: Generics (Updated)
Section: Type Erasure

Effects of Type Erasure and Bridge Methods类型擦除和桥接方法的影响

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

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, 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:类型擦除后,NodeMyNode类变为:

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


Previous page: Erasure of Generic Methods
Next page: Non-Reifiable Types