Method.isBridge用于什么?

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

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

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

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

请参见创建框架,同步,传输控制 :

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

 class C { abstract T id(T x); } class D extends C { 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(); 

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

考虑以下界面和function:

 public static interface Function { public R apply (A arg); } public static  R applyFunc (Function func, A arg) { return func.apply(arg); } 

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

 Function lower = new Function() { 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 lower = ...; lower.apply("Hello"); 

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

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

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

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

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