在Method類的導航過程中,我遇到了函數isBridge(),它的javadoc說它只有在Java規範聲明方法爲true時才爲真。什麼java.lang.reflect.Method.isBridge()用於?
請幫我理解這是用來做什麼的?如果需要,自定義類是否可以將其方法聲明爲橋?
在Method類的導航過程中,我遇到了函數isBridge(),它的javadoc說它只有在Java規範聲明方法爲true時才爲真。什麼java.lang.reflect.Method.isBridge()用於?
請幫我理解這是用來做什麼的?如果需要,自定義類是否可以將其方法聲明爲橋?
當擴展參數化類型,其方法具有參數化參數時,編譯器可能會創建一個橋接方法。
你可以在此類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請參見:
在註釋中,還需要爲協變重寫橋方法:
通常,Object clone()
可由MyObject clone()
被覆蓋的方法,但會被編譯器產生的電橋法:
public bridge Object MyObject.clone();
那裏所示的例子(從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");
另一種情況下,我偶然發現與泛型無關:
protected abstract class Super {
public void m() {}
}
public class Sub extends Super {}
assert Sub.class.getMethod("m").isBridge();
即使沒有泛型,橋接方法也是協變返回類型所必需的。 – 2008-11-14 11:51:21