Section 3.7. Bridges


3.7. Bridges

As we mentioned earlier, generics are implemented by erasure: when you write code with generics, it compiles in almost exactly the same way as the code you would have written without generics. In the case of a parameterized interface such as Comparable<T>, this may cause additional methods to be inserted by the compiler; these additional methods are called bridges.

Example 3.6 shows the Comparable interface and a simplified version of the Integer class in Java before generics. In the nongeneric interface, the compareTo method takes an argument of type Object. In the nongeneric class, there are two compareTo methods. The first is the naïve method you might expect, to compare an integer with another integer. The second compares an integer with an arbitrary object: it casts the object to an integer and calls the first method. The second method is necessary in order to override the compareTo method in the Comparable interface, because overriding occurs only when the method signatures are identical. This second method is called a bridge.

Example 3-6. Legacy code for comparable integers

 interface Comparable {   public int compareTo(Object o); } class Integer implements Comparable {   private final int value;   public Integer(int value) { this.value = value; }   public int compareTo(Object o) {     return compareTo((Integer)o);   }   public int compareTo(Integer i) {     return (value < i.value) ? -1 : (value == i.value) ? 0 : 1;   } } 

Example 3.7 shows what happens when the Comparable interface and the Integer class are generified. In the generic interface, the compareTo method takes an argument of type T. In the generic class, a single compareTo method takes an argument of type Integer. The bridge method is generated automatically by the compiler. Indeed, the compiled version of the code for both examples is essentially identical.

Example 3-7. Generic code for comparable integers

 interface Comparable<T> {   public int compareTo(T o); } class Integer implements Comparable<Integer> {   private final int value;   public Integer(int value) { this.value = value; }   public int compareTo(Integer i) {     return (value < i.value) ? -1 : (value == i.value) ? 0 : 1;   } } 

You can see the bridge if you apply reflection. Here is code that finds all methods with the name compareTo in the class Integer, using toGenericString to print the generic signature of a method (see Section 7.5).

 for (Method m : Integer.class.getMethods())     if (m.getName().equals("compareTo"))         System.out.println(m.toGenericString()); 

Running this code on the generic version of the Integer class produces the following output:

 public int Integer.compareTo(Integer) public bridge int Integer.compareTo(java.lang.Object) 

This indeed contains two methods, both the declared method that takes an argument of type Integer and the bridge method that takes an argument of type Object. (As of this writing, the Sun JVM prints volatile instead of bridge, because the bit used in Java bytecode to indicate bridge methods is also used to indicate volatile fields; this bug is expected to be fixed in a future release.)

Bridges can play an important role when converting legacy code to use generics; see Section 8.4.




Java Generics and Collections
Java Generics and Collections
ISBN: 0596527756
EAN: 2147483647
Year: 2006
Pages: 136

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net