Documentation

The Java™ Tutorials
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 = mn; // A raw type - compiler throws an unchecked warning // Note: This statement could instead be the following: // Node n = (Node)mn; // However, the compiler doesn't generate a cast because // it isn't required. n.setData("Hello"); // Causes a ClassCastException to be thrown. Integer x = (Integer)mn.data; 

The next section explains why a ClassCastException is thrown at the n.setData("Hello"); statement.

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:

 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). As a result, the MyNode.setData(Integer) method does not override the Node.setData(Object) method.

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.

For the MyNode class, the compiler generates the following bridge method for 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. 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.


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