What is a bridge method in Java, and why does the compiler generate one when a generic supertype is overridden?
answer
- erasure makes super = compareTo(Object), sub = compareTo(MyType) — signatures differ
- compiler adds compareTo(Object) that casts + forwards
- restores polymorphic override after erasure
- flags: ACC_SYNTHETIC + ACC_BRIDGE; Method.isBridge()/isSynthetic()
- javap -p shows the extra method
basics
~20 sA bridge method is an extra method the compiler adds automatically when you override a method from a generic class or interface. It exists so that overriding still works after generics are erased to raw types at compile time.
solid answer
~40 sJava generics use type erasure: at compile time the type parameter is replaced by its bound (or Object), so a generic supertype's method ends up with an erased signature like compareTo(Object). When a subclass overrides it with a specific type, e.g. compareTo(MyType), the two signatures no longer match, so plain method overriding would break. To fix this the compiler emits a synthetic bridge method with the erased signature compareTo(Object) that simply casts its argument and forwards to the real compareTo(MyType). This restores correct polymorphic dispatch: a caller holding the supertype reference invokes the erased signature, the bridge runs, and the call lands on your real override. Bridge methods are marked synthetic and bridge in the bytecode and never appear in source; you only see them via reflection or a bytecode dump.
code
java · 18 linesclass MyDate implements Comparable<MyDate> {
private final long millis;
MyDate(long millis) { this.millis = millis; }
// You write this:
public int compareTo(MyDate other) {
return Long.compare(this.millis, other.millis);
}
// The compiler generates (conceptually):
// public int compareTo(Object other) { // ACC_BRIDGE, ACC_SYNTHETIC
// return compareTo((MyDate) other); // cast + forward
// }
}
// Observe it:
// for (var m : MyDate.class.getDeclaredMethods())
// System.out.println(m + " bridge=" + m.isBridge());go deeper
Knows generics get erased and that the compiler sometimes adds hidden methods, but may not name them precisely. Can state that overriding a generic method still works.
Can explain that erasure makes the super signature use Object, the sub signature use the specific type, and the compiler inserts a forwarding bridge so the override still dispatches correctly.
Articulates the exact mechanism (erased vs specific signature mismatch), the cast-and-forward body, the ACC_BRIDGE/ACC_SYNTHETIC flags, and reflection implications (isBridge filtering).
Frames it in the larger erasure/backward-compatibility design tradeoff, contrasts with reified generics, and reasons about edge cases (covariant returns, multiple bridges, ClassCastException as the heap-pollution guard) and library/tooling impact.
## Background you need first **Generics** let you write a class or method parameterized by a type, e.g. `Comparable<T>`. **Type erasure** is the way Java implements generics: the JVM bytecode has no notion of `T`. At compile time, every type parameter is *erased* — replaced by its leftmost bound, or by `Object` if it has no bound. So `Comparable<T>` becomes, in bytecode, `Comparable` with a method `int compareTo(Object)`. This keeps generics backward-compatible with pre-2004 (pre-Java-5) bytecode and lets generic and non-generic code interoperate. **Overriding** means a subclass method with the *same signature* (name + parameter types) as a superclass/interface method replaces it for polymorphic dispatch. The JVM matches overrides by exact erased signature. ## The problem erasure creates Suppose you write: ```java class MyDate implements Comparable<MyDate> { public int compareTo(MyDate other) { ... } } ``` In source this *looks* like an override of `Comparable<MyDate>.compareTo(MyDate)`. But after erasure the interface only declares `int compareTo(Object)`. Your class declares `int compareTo(MyDate)`. These are **different signatures** — `compareTo(Object)` vs `compareTo(MyDate)` — so at the bytecode level your method does NOT override the interface method. If nothing were done, a call through a `Comparable` reference (which targets `compareTo(Object)`) would not reach your `compareTo(MyDate)`, breaking polymorphism. ## The fix: a synthetic bridge method The compiler closes the gap by generating an extra method in `MyDate`: ```java // generated by the compiler, not written by you public int compareTo(Object other) { return compareTo((MyDate) other); // cast + forward to the real method } ``` This is the **bridge method**. It has the *erased* signature `compareTo(Object)`, so it genuinely overrides the interface method, and its body casts the argument and delegates to your real, type-specific `compareTo(MyDate)`. Now a caller using the supertype invokes `compareTo(Object)`, lands on the bridge, which forwards to your code. Polymorphism is restored. ## How to recognize it The bridge method is flagged with two access flags in the class file: `ACC_SYNTHETIC` (compiler-generated, not in source) and `ACC_BRIDGE`. You can see it with `javap -p` (it shows the extra `compareTo(java.lang.Object)`), or via reflection: `Method.isBridge()` returns `true` and `Method.isSynthetic()` returns `true`. It never appears in your source code. ## Why "bridge" It *bridges* the erased supertype signature to your real specific-type signature, so two worlds — the type-erased view the JVM/old callers see, and the parameterized view you wrote — connect correctly. ## Consequences to remember - There can be *two* methods named `compareTo` in the bytecode of `MyDate`: yours and the bridge. This is legal in bytecode even though it would look like a duplicate in source. - Reflection that lists declared methods will return the bridge too — code that iterates methods should usually skip `m.isBridge()` ones. - The bridge does an unchecked cast `(MyDate) other`; if someone calls it with the wrong runtime type, a `ClassCastException` is thrown inside the bridge, which is exactly the heap-pollution protection erasure otherwise loses.
- How can you observe a bridge method at runtime?Use reflection: iterate getDeclaredMethods() and check Method.isBridge() (and isSynthetic()), or inspect the bytecode with javap -p, which lists the extra erased-signature method flagged ACC_BRIDGE/ACC_SYNTHETIC.
- What exception can a bridge method throw that the real method wouldn't?A ClassCastException, because the bridge performs an unchecked downcast from the erased parameter (e.g. Object) to the specific type before forwarding.
saying these in an interview costs you the question
- Saying you write bridge methods yourself — they are compiler-generated only.
- Claiming generics are reified in Java like in C# — Java uses erasure, which is the whole reason bridges exist.
- Thinking the bridge is just a duplicate/overload with no purpose — it is the actual override the JVM dispatches to.
- Saying erasure replaces T with Object always — it replaces with the leftmost bound, Object only when unbounded.