方法.是桥的用途?

2022-09-01 12:07:55

在类的导航过程中,我遇到了方法。它的 Javadoc 表示,仅当 Java 规范将方法声明为 true 时,它才会返回 true。java.lang.reflect.MethodisBridge

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


答案 1

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

您可以在此类中找到BridgeMethodResolver一种获取“bridge方法”引用的实际方法的方法。

请参阅创建帧、同步、传输控制

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

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

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

仅当程序引起未经检查的警告(§5.1.9)时,才会出现这种情况。

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

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

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

另请参阅桥:

如注释中所述,协变覆盖也需要桥接方法:

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

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

public bridge Object MyObject.clone();

答案 2

这里显示的示例(引自 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");

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

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

有趣的是,只有当类使用签名实现其他接口时,并且仅当通过该接口类型的引用调用该方法时,编译器才会发出带有该签名的调用。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");