Method.isBridge用于什么?

时间:2008-11-14 10:37:43

标签: java api reflection

在导航java.lang.reflect.Method课程期间,我遇到了方法isBridge。它的Javadoc说它只有在Java规范声明方法为真时才返回true。

请帮我理解这是用来做什么的!如果需要,自定义类可以将其方法声明为桥接吗?

3 个答案:

答案 0 :(得分:27)

当扩展其方法具有参数化参数的参数化类型时,编译器可以创建桥接方法。

您可以在此课程BridgeMethodResolver中找到一种方法来获取由“桥接方法”引用的实际方法。

请参阅Create Frame, Synchronize, Transfer Control

作为这种情况的一个例子,请考虑声明:

class C<T> { abstract T id(T x); }
class D extends C<String> { String id(String x) { return x; } }

现在,给定一个调用

C c = new D();
c.id(new Object()); // fails with a ClassCastException

正在调用的实际方法的擦除,D.id(String)的签名与编译时方法声明C.id(Object)的签名不同。前者采用String类型的参数,而后者采用Object类型的参数。在执行方法体之前,调用失败并带有ClassCastException。

只有在程序产生未经检查的警告(§5.1.9)时才会出现这种情况。

实现可以通过创建桥接方法来强制实施这些语义。在上面的示例中,将在D类中创建以下桥接方法:

Object id(Object x) { return id((String) x); }

这是Java虚拟机响应上面显示的调用c.id(new Object())实际调用的方法,它将根据需要执行强制转换和失败。

另请参阅 Bridge

如评论中所述,协变覆盖还需要桥接方法:

  • 在Java 1.4及更早版本中,如果签名匹配,则一种方法可以覆盖另一种方法 准确。
  • 在Java 5中,如果参数与完全匹配,则方法可以覆盖另一个方法,但如果它是返回类型的子类型,则覆盖方法的返回类型另一种方法。

通常,方法Object clone()可以被MyObject clone()覆盖,但编译器将生成桥接方法:

public bridge Object MyObject.clone();

答案 1 :(得分:3)

那里显示的示例(引自JLS)使得听起来像桥接方法仅用于使用原始类型的情况。由于情况并非如此,我认为我将使用桥接方法用于完全类型正确的通用代码的示例。

考虑以下界面和功能:

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);
}

如果以下列方式使用此代码,则使用桥接方法:

Function<String, String> lower = new Function<String, String>() {
    public String apply (String arg) {
        return arg.toLowerCase();
    }
};
applyFunc(lower, "Hello");

擦除后,Function接口包含方法apply(Object)Object(您可以通过反编译字节码来确认)。当然,如果您查看applyFunc的反编译代码,您会看到它包含对apply(Object)Object的调用。 Object是其类型变量的上限,因此没有其他签名有意义。

因此,当使用方法apply(String)String创建匿名类时,除非创建了桥接方法,否则它实际上不会实现Function接口。 bridge方法允许所有通用类型的代码使用Function实现。

有趣的是,只有当类使用签名apply(String)String实现了一些其他接口时,并且只有当通过该接口类型的引用调用该方法时,编译器才会发出调用签名。

即使我有以下代码:

Function<String, String> lower = ...;
lower.apply("Hello");

编译器仍然会调用apply(Object)Object

实际上还有另外一种方法可以让编译器调用apply(String)String,但它利用了分配给匿名类创建表达式的魔法类型,否则无法写下来:

new Function<String, String>() {
    public String apply (String arg) {
        return arg.toLowerCase();
    }
}.apply("Hello");

答案 2 :(得分:0)

我偶然发现的另一个案例与泛型无关:

protected abstract class Super {
    public void m() {}
}
public class Sub extends Super {}
assert Sub.class.getMethod("m").isBridge();