The example shown there (quoted from the JLS) makes it sound like bridge methods are only used in situations where raw types are used. Since this is not the case, I thought I'd pipe in with an example where bridge methods are used for totally type-correct generic code.
Consider the following interface and function:
public static interface Function<A,R> {
public R apply (A arg);
}
public static <A, R> R applyFunc (Function<A,R> func, A arg) {
return func.apply(arg);
}
If you use this code in the following way, a bridge method is used:
Function<String, String> lower = new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
};
applyFunc(lower, "Hello");
After erasure, the Function
interface contains the method apply(Object)Object
(which you can confirm by decompiling the bytecode). Naturally, if you look at the decompiled code for applyFunc
you'll see that it contains a call to apply(Object)Object
. Object
is the upper bound of its type variables, so no other signature would make sense.
So when an anonymous class is created with the method apply(String)String
, it doesn't actually implement the Function
interface unless a bridge method is created. The bridge method allows all generically typed code to make use of that Function
implementation.
Interestingly, only if the class implemented some other interface with the signature apply(String)String
and only if the method was called via a reference of that interface type would the compiler ever emit a call with that signature.
Even if I have the following code:
Function<String, String> lower = ...;
lower.apply("Hello");
The compiler still emits a call to apply(Object)Object
.
There is actually one other way to get the compiler to call apply(String)String
, but it takes advantage of the magical type assigned to an anonymous class creation expression which cannot otherwise be written down:
new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
}.apply("Hello");