考慮這個例子:
Function<String, Integer> function = String::length;
Function rawFunction = function; // warning: unchecked conversion
rawFunction.apply(new Object()); // warning: unchecked call
最后一行將給出java.lang.ClassCastException: class java.lang. Object cannot be cast to class java.lang.String. 這對我來說并不奇怪,因為函式被宣告為接受字串。
我知道原始型別可以給出 ClassCastException,但我看到的所有示例都是關于未經檢查的呼叫回傳物件上的 ClassCastException 而不是方法引數:我??可以找到編譯器在位元組碼中為回傳物件添加的強制轉換,但不能用于引數。在哪里指定此行為?如果不是位元組碼中的指令,究竟是什么導致了我的示例中的 ClassCastException?
uj5u.com熱心網友回復:
泛型處理方法引數的方式是通過合成橋接方法。
例如,對于Function介面 - 其原始引數接受Object,但非原始引數接受任何,您必須有一個接受 的方法Object。
當我反編譯上面的代碼時,我在位元組碼中得到了一行:
16: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
所以它實際上是在嘗試呼叫一個apply以 anObject作為引數的方法。這種方法存在于 上Function,這就是合成橋法。
如果你這樣寫Function:
class MyFunction implements Function<String, Integer> {
@Override public Integer apply(String input) {
return null;
}
}
然后反編譯,你會發現里面還有一個方法:
final class MyFunction implements java.util.function.Function<java.lang.String, java.lang.Integer> {
// Default constructor, as you'd expect.
MyFunction();
// The apply method as defined above.
public java.lang.Integer apply(java.lang.String);
// What's this?!
public java.lang.Object apply(java.lang.Object);
}
該public java.lang.Object apply(java.lang.Object)方法已被添加。這就是合成橋法。
它的位元組碼看起來像:
public java.lang.Object apply(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #2 // class java/lang/String
5: invokevirtual #3 // Method apply:(Ljava/lang/String;)Ljava/lang/Integer;
8: areturn
這類似于:
public Object apply(Object input) {
return apply((String) input);
}
因此,合成橋接方法只呼叫“非原始”應用方法。所以,ClassCastException來源于那投合成橋法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/323585.html
