2008-11-14 59 views
27

在Method類的導航過程中,我遇到了函數isBridge(),它的javadoc說它只有在Java規範聲明方法爲true時才爲真。什麼java.lang.reflect.Method.isBridge()用於?

請幫我理解這是用來做什麼的?如果需要,自定義類是否可以將其方法聲明爲橋?

回答

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(); 
+2

即使沒有泛型,橋接方法也是協變返回類型所必需的。 – 2008-11-14 11:51:21

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。橋接方法允許所有一般類型的代碼使用該實現。有趣的是,只有當類實現了一些其他接口與簽名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"); 
0

另一種情況下,我偶然發現與泛型無關:

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