Spec-Zone .ru
спецификации, руководства, описания, API
|
Иногда вводите причины стирания ситуация, которую Вы, возможно, не ожидали. Следующий пример показывает, как это может произойти. Пример (описанный в Мостовых методах) показывает, как компилятор иногда создает синтетический метод, названный мостовым методом, как часть процесса стирания типа.
Учитывая следующие два класса:
public class Node<T> { private 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.
Вот то, что происходит, поскольку код выполняется:
Компилируя class или интерфейс, который расширяет параметризованный class или реализует параметризованный интерфейс, компилятор, возможно, должен создать синтетический метод, названный мостовым методом, как часть процесса стирания типа. Вы обычно не должны волноваться о мостовых методах, но Вы могли бы быть озадачены, если Вы появляетесь в трассировке стека.
После стирания типа Node и классы MyNode становятся:
public class Node { private 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(Integer data); super.setData(data); } }
После стирания типа не не соответствуют сигнатуры методов. Метод Node становится setData(Object), и метод MyNode становится setData(Integer). Поэтому, метод MyNode setData не переопределяет метод Node setData.
Чтобы решить эту проблему и сохранить полиморфизм универсальных типов после стирания типа, компилятор Java генерирует мостовой метод, чтобы гарантировать тому выделению подтипов работы как ожидалось. Для MyNode class компилятор генерирует следующий мостовой метод для 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 class Node после стирания типа, делегатов в исходном методе setData.