Bridge Methods in Java

Naveen AnamaneniUpdated · 4 min read
hardJava 25javagenericsjvm

When you write class Marks implements Comparable<Marks> with a compareTo(Marks other) method, you're overriding Comparable's compareTo(T other). But after type erasure, Comparable really declares compareTo(Object other). Your method's parameter is Marks, not Object, so to the JVM it doesn't override anything. The compiler quietly fixes this by adding a bridge method: a hidden compareTo(Object) that casts and calls yours.

Seeing the Bridge

Ranking.java▶ Try it
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
 
public class Ranking {
    static class Marks implements Comparable<Marks> {
        final String name;
        final int value;
 
        Marks(String name, int value) {
            this.name = name;
            this.value = value;
        }
 
        @Override
        public int compareTo(Marks other) {
            return Integer.compare(value, other.value);
        }
    }
 
    public static void main(String[] args) {
        for (Method m : Marks.class.getDeclaredMethods()) {
            if (m.getName().equals("compareTo")) {
                System.out.println(Arrays.toString(m.getParameterTypes())
                    + " bridge=" + m.isBridge());
            }
        }
        List<Marks> list = Arrays.asList(new Marks("Navika", 91),
            new Marks("Srihitha", 88), new Marks("Advitha", 95));
        list.sort(null);
        System.out.println(list.get(0).name + " is lowest");
    }
}
Output
[class Ranking$Marks] bridge=false
[class java.lang.Object] bridge=true
Srihitha is lowest

How it works

  1. The class has two compareTo methods: yours, taking Marks, and a bridge taking Object, which the reflection API reports with isBridge() = true. (Their order in the list can vary.)
  2. Sorting code calls compareTo(Object) through the erased Comparable interface. That reaches the bridge, which casts the argument to Marks and calls your method.

javap shows what the bridge does:

javap -p -c Bridge$Marks (trimmed)
  public int compareTo(Bridge$Marks);
  public int compareTo(java.lang.Object);
    Code:
         0: aload_0
         1: aload_1
         2: checkcast     #8          // class Bridge$Marks
         5: invokevirtual #19         // Method compareTo:(LBridge$Marks;)I
         8: ireturn
The bridge connects the erased signature to your method

When Bridges Appear

SituationBridge generated
Implementing a generic interface with a concrete type: Comparable<Marks>compareTo(Object)
Extending a generic class and overriding with a concrete typeA method with the parent's erased signature
A covariant return type (see "Covariant Return Type in Java")A method with the parent's return type

You never write or call bridge methods yourself. You'll notice them only in javap output, in stack traces (where they can appear as an extra line at the same source line), and when using reflection, where isBridge() lets frameworks skip them.

Common Mistakes

Being confused by two compareTo methods in reflection output. One is the bridge; check isBridge().

Trying to write compareTo(Object) yourself as well. It clashes with the bridge's signature.

Thinking bridges slow programs down. The JIT inlines them; the cost is negligible.

Practice

  1. Easy: Run javap -p on a class implementing Comparator<String> and find the bridge for compare.
  2. Harder: Write class Box<T> { T get() { return null; } } and class NameBox extends Box<String> { @Override String get() { return "Navika"; } }. Use reflection to list NameBox's get methods and mark which is the bridge.

Quick check: Bridge methods

4 questions
1Who writes a bridge method?
2Why is compareTo(Object) needed in a class implementing Comparable?
3What does the bridge do?
4How can reflection tell a bridge apart?

Key Takeaways

Was this tutorial helpful?

Lesson 249 of 482