# 类型擦除和桥梁方法的影响

> 原文： [https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html](https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html)

有时类型擦除会导致您可能没有预料到的情况。以下示例显示了如何发生这种情况。该示例（在[桥接方法](#bridgeMethods)中描述）显示了编译器有时如何创建合成方法，称为桥接方法，作为类型擦除过程的一部分。

给出以下两个类：

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

```

请考虑以下代码：

```
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.

```

在类型擦除后，此代码变为：

```
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.

```

以下是执行代码时发生的情况：

*   `n.setData（“你好”）;` 导致方法 `setData（Object）`在类 `MyNode` 的对象上执行。 （ `MyNode` 类从`节点`继承 `setData（Object）`。）
*   在 `setData（Object）`的主体中， `n` 引用的对象的数据字段被分配给 `String` 。
*   通过 `mn` 引用的同一对象的数据字段可以被访问并且预期是整数（因为 `mn` 是 `MyNode` ，它是`节点&lt;整数&gt;` 。
*   尝试将`字符串`分配给`整数`会导致 `ClassCastException` 来自 Java 编译器在赋值时插入的强制转换。

在编译扩展参数化类或实现参数化接口的类或接口时，编译器可能需要创建一个称为 _ 桥接方法 _ 的合成​​方法，作为类型擦除过程的一部分。您通常不需要担心桥接方法，但如果出现在堆栈跟踪中，您可能会感到困惑。

在类型擦除之后，`节点`和 `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);
    }
}

```

在类型擦除之后，方法签名不匹配。 `节点`方法变为 `setData（Object）`， `MyNode` 方法变为 `setData（Integer）`。因此， `MyNode` `setData` 方法不会覆盖`节点` `setData` 方法。

为了解决这个问题并在类型擦除后保留泛型类型的[多态](../IandI/polymorphism.html)，Java 编译器会生成一个桥接方法，以确保子类型按预期工作。对于 `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);
    }

    // ...
}

```

如您所见，桥接方法与类型擦除后的`节点`类的 `setData` 方法具有相同的方法签名，委托给原始的 `setData` 方法。