Java – Bridges in Generics

In the non-Generics Java world (JDK 1.4 or before) we would have noticed all wrapper classes that implement Comparable interface has got two compareTo methods as shown below:

public interface Comparable {
      public int compareTo( object obj );
}

public final class Long extends Number implements Comparable {

   //Override
   public int compareTo( Object obj ) {
      //throws ClassCastException if the obj is not of type Long
      return compareTo( (Long)obj );
   }

   public int compareTo( Long anotherLong) {
      //logic for comparing two Long objects.
      return result;
   }
}
  • A convenient method taking in an argument of type Long for comparison.
  • And the one that’s implemented as a result of implementing Comparable interface which takes in an argument of type Object. This method internally casts the incoming object to the given class type (Long) and delegates the call to the convenient compareTo method as shown above. If it couldn’t cast, then a ClassCastException is thown. We call this method as ‘bridge‘ method.

But Post Java 5, with introduction of Generics and type safety, things have improved and we no more need the bridge method, compareTo(Object o) and doesn’t have to worry about any ClassCastException anymore. The implementation of the wrapper class, Long,  in Java 5 or above looks as follows:

public interface Comparable<T> {
   public int compareTo(T o);
}

public final class Long extends Number implements Comparable<Long> {

   @Override
   public int compareTo(Long anotherLong) {
           //logic for comparing to Long objects
           return result;
   }
}

But hold on second, isn’t Java 5 and above compilers has got something called type erasure, a process where the compiler will remove all the information related to type parameters and type arguments within a class or method for the sake of being binary compatible with Java libraries/applications that were created before generics?

Doesn’t it mean that the above Java 5 Long code after compilation should get translated as it is in the Java 1.4 versions? If that’s the case, where does the bridge method go which maintains the contract between Long and Comparable interface? Things are suppose to break here. But it actually doesn’t why?

Thats where ‘Bridges‘ in Generics comes into picture. When the compiler translates the code for binary compatibility with older applications, it also adds the required bridge methods automatically in order to sustain the implementation contracts. In this case the contract between Comparable and the class(Long) that is implementing it.

This simple snippet of reflection code run on Long.class reveals the secret.

final Method[] methods = Long.class.getDeclaredMethods();
for (Method method : methods) {
        System.out.println(method.toString() +
           " - IsBrige?:" + method.isBridge());
}

Output:
.....
public int java.lang.Long.compareTo(java.lang.Long) - IsBrige?:false
public int java.lang.Long.compareTo(java.lang.Object) - IsBrige?:true
......

Advertisements

About this entry