Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What Method.isBridge used for?

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?

like image 794
Nrj Avatar asked Nov 14 '08 10:11

Nrj


2 Answers

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:

  • In Java 1.4, and earlier, one method can override another if the signatures match exactly.
  • In Java 5, a method can override another if the arguments match exactly but the return type of the overriding method, if it is a subtype of the return type of the other method.

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(); 
like image 58
VonC Avatar answered Oct 04 '22 05:10

VonC


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");
like image 35
samskivert Avatar answered Oct 04 '22 05:10

samskivert