GEEK SNACK

Venkatesh R S
ThoughtWorks
Nov 18, 2009 Episode 6

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 have 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 ) { return compareTo( (Long)obj ); } public int compareTo( Long anotherLong) { //compare two long objects return result; } } A convenient, compareTo(Long) method which implements the logic for comparison. And the compareTo(Object) method from Comparable interface acts as a 'bridge' method by delegating its call to the compareTo(Long long) as shown above. 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 final class Long extends Number implements Comparable<Long> { @Override public int compareTo(Long other) { //compare both 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? That’s 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 is between Comparable and the class(Long) that is implementing it. The following snippet of reflection code for the Long.class should reveal 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.Lon g) - IsBrige?:false public int java.lang.Long.compareTo(java.lang.Obj ect) - IsBrige?:true ......