During navigation of the java.lang.reflect.Method
class I came across the method isBridge
. Its Javadoc says that it returns true only if the Java spec declares the method as true.
Please help me understand what this is used for! Can a custom class declare its method as a bridge if required?
A bridge method may be created by the compiler when extending a parameterized type whose methods have parameterized arguments.
You can find in this class BridgeMethodResolver a way to get the actual Method referred by a 'bridge method'.
See Create Frame, Synchronize, Transfer Control:
As an example of such a situation, consider the declarations:
class C<T> { abstract T id(T x); } class D extends C<String> { String id(String x) { return x; } }
Now, given an invocation
C c = new D(); c.id(new Object()); // fails with a ClassCastException
The erasure of the actual method being invoked, D.id(String)
differs in its signature from that of the compile-time method declaration, C.id(Object)
. The former takes an argument of type String while the latter takes an argument of type Object. The invocation fails with a ClassCastException before the body of the method is executed.
Such situations can only arise if the program gives rise to an unchecked warning (§5.1.9).
Implementations can enforce these semantics by creating bridge methods. In the above example, the following bridge method would be created in class D:
Object id(Object x) { return id((String) x); }
This is the method that would actually be invoked by the Java virtual machine in response to the call c.id(new Object())
shown above, and it will execute the cast and fail, as required.
See also Bridge:
as mentioned in the comment, bridge methods are also needed for covariant overriding:
Typically, a method Object clone()
can be overridden by a MyObject clone()
, but a bridge method will be generated by the compiler:
public bridge Object MyObject.clone();
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");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With