Wednesday, November 18, 2009

Java – Bridges in Generics - By Venkat RS

Download this one-page Geek snack episode, and place it at your snack area.

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) {

//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:

publicfinalclassLongextendsNumberimplementsComparable<Long> {

@Override

publicint 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?

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.