Tuesday 19 October 2021

What is bridge method in Java?

Sometimes to support type-erasure use case of generics, Java compiler creates a synthetic method, which is called a bridge method, as part of the type erasure process.

 

What is type erasure?

Type Erasure is a process, where Java Compiler replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.

 

Box.java

public class Box<T> {

    private T data;

    public Box(T data) {
        this.data = data;
    }

    public T getData() { return data; }

}

 

In the above example, "T" is unbounded type. So Java Compiler replaces Every Occurrence of T with Object.

public class Box {

    private Object data;

    public Box(Object data) {
        this.data = data;
    }

    public Object getData() { return data; }

}

Consider one more Example

public class Box<T extends Integer> {

    private T data;

    public Box(T data) {
        this.data = data;
    }

    public T getData() { return data; }

}


After type Erasure, Type Parameter “T” is replaced with Integer.


public class Box{

    private Integer data;

    public Box(Integer data) {
        this.data = data;
    }

    public Integer getData() { return data; }

}

 

Bridge method

Sometimes to support type-erasure use case of generics, Java compiler creates a synthetic method, which is called a bridge method, as part of the type erasure process.

 

Let me explain it with an example.

 

Container.java

 

package com.sample.app;

public class Container<T> {

	public T data;

	public Container(T data) {
		this.data = data;
	}

	public void setData(T data) {
		this.data = data;
	}
}

 

IntegerContainer.java

package com.sample.app;

public class IntegerContainer extends Container<Integer> {

	public IntegerContainer(Integer data) {
		super(data);
	}

	public void setData(Integer data) {
		super.setData(data);
	}
}

 

Consider the following code.

IntegerContainer integerContainer = new IntegerContainer(5);

// A raw type - compiler throws an unchecked warning
Container container = integerContainer;

// Below statement throws a ClassCastException
container.setData("Hello");
Integer x = integerContainer.data;
After type erasure, this code becomes like below.

IntegerContainer integerContainer = new IntegerContainer(5);
Container container = (Container)integerContainer;         
container.setData("Hello");         
Integer x = (String)integerContainer.data;

 

As I said previously, in some situations, as part of type erasure process, Java compiler creates a synthetic method called bridge method.

 

After type erasure, the method signatures do not match; the Container.setData(T) method becomes Container.setData(Object). As a result, the IntegerContainer.setData(Integer) method does not override the Container.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.When you decompile the class file ‘IntegerContainer.class’, it contains below code snippet.

$javap -c com/sample/app/IntegerContainer.class 
Compiled from "IntegerContainer.java"
public class com.sample.app.IntegerContainer extends com.sample.app.Container<java.lang.Integer> {
  public com.sample.app.IntegerContainer(java.lang.Integer);
    Code:
       0: aload_0
       1: aload_1
       2: invokespecial #1                  // Method com/sample/app/Container."<init>":(Ljava/lang/Object;)V
       5: return

  public void setData(java.lang.Integer);
    Code:
       0: aload_0
       1: aload_1
       2: invokespecial #2                  // Method com/sample/app/Container.setData:(Ljava/lang/Object;)V
       5: return

  public void setData(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #3                  // class java/lang/Integer
       5: invokevirtual #4                  // Method setData:(Ljava/lang/Integer;)V
       8: return
}

 

As you see above snippet, you can confirm that compiler generates a synthetic (bridge) method ‘public void setData(java.lang.Object);’,

 

The bridge method IntegerContainer.setData(object) delegates to the original IntegerContainer.setData(Integer) method. As a result, the container.setData("Hello"); statement calls the method IntegerContainer.setData(Object), and a ClassCastException is thrown because "Hello" can't be cast to Integer.

 

 

 

 

You may like

Interview Questions

Is below statement compile?

Versioning History of Java

Understanding ConcurrentModificationException in Java

Remove oldest entry from the map

Synthetic constructs in Java

No comments:

Post a Comment