Java Generics - Bridge method?

If you want to understand why you need bridge method, you better understand what happens without it. Suppose there is no bridge method.

class A<T>{
  private T value;
  public void set(T newVal){
    value=newVal
  }
}

class B extends A<String>{
  public void set(String newVal){
    System.out.println(newVal);
    super.set(newVal);
  }
}

Notice that after erasure, method set in A became public void set(Object newVal) since there is no bound on Type parameter T. There is no method in class B the signature of which is the same as set in A. So there is no override. Hence, when something like this happened:

A a=new B();
a.set("Hello World!");

Polymorphism won't work here. Remember you need to override the method of parent class in child class so that you can use parent class var to trigger polymorphism.

What bridge method does is silently override the method in parent class with all the information from a method with the same name but a different signature. With the help of the bridge method, polymorphism worked. Though on the surface, you override the parent class method with a method of different signature.


It's a method that allows a class extending a generic class or implementing a generic interface (with a concrete type parameter) to still be used as a raw type.

Imagine this:

public class MyComparator implements Comparator<Integer> {
   public int compare(Integer a, Integer b) {
      //
   }
}

This can't be used in its raw form, passing two Objects to compare, because the types are compiled in to the compare method (contrary to what would happen were it a generic type parameter T, where the type would be erased). So instead, behind the scenes, the compiler adds a "bridge method", which looks something like this (were it Java source):

public class MyComparator implements Comparator<Integer> {
   public int compare(Integer a, Integer b) {
      //
   }

   //THIS is a "bridge method"
   public int compare(Object a, Object b) {
      return compare((Integer)a, (Integer)b);
   }
}

The compiler protects access to the bridge method, enforcing that explicit calls directly to it result in a compile time error. Now the class can be used in its raw form as well:

Object a = 5;
Object b = 6;

Comparator rawComp = new MyComparator();
int comp = rawComp.compare(a, b);

Why else is it needed?

In addition to adding support for explicit use of raw types (which is mainly for backwards compatability) bridge methods are also required to support type erasure. With type erasure, a method like this:

public <T> T max(List<T> list, Comparator<T> comp) {
   T biggestSoFar = list.get(0);
   for ( T t : list ) {
       if (comp.compare(t, biggestSoFar) > 0) {
          biggestSoFar = t;
       }
   }
   return biggestSoFar;
}

is actually compiled into bytecode compatible with this:

public Object max(List list, Comparator comp) {
   Object biggestSoFar = list.get(0);
   for ( Object  t : list ) {
       if (comp.compare(t, biggestSoFar) > 0) {  //IMPORTANT
          biggestSoFar = t;
       }
   }
   return biggestSoFar;
}

If the bridge method didn't exist and you passed a List<Integer> and a MyComparator to this function, the call at the line tagged IMPORTANT would fail since MyComparator would have no method called compare that takes two Objects...only one that takes two Integers.

The FAQ below is a good read.

See Also:

  • The Generics FAQ - What is a bridge method?
  • Java bridge methods explained (thanks @Bozho)

Tags:

Java

Generics