2017-04-27 49 views
0

有一個類A可以某種方式映射到另一個類B或其他一個:爲什麼返回的函數需要額外的投射(不兼容的類型)?

class A {} 

class B { 
    final A a; 

    B(A a) { 
     this.a = a; 
    } 
} 

還有一個映射器工廠,從A返回映射器基於作爲參數傳遞的第二類的類型另一個類:

class Mapper { 

    static Function<A, B> a2bmapper = B::new; 

    static <R> Function<A, R> findMapper(Class<R> cls) { 
     if(cls == B.class) { 
      return a2bmapper; 
     } 
     return null; 
    }   
} 

的問題是,在這條線:

return a2bmapper; 

java編譯器問題不兼容類型:必需R,找到B,IDE建議將其轉換爲Function<A,R>。這是爲什麼? R只是一個通用類型,應該用B代替。

+4

簡短的答案是類型系統可以檢查很多,但它不能檢查_everything_。侷限性(理論和實踐,就時間和投入到語言規範和編譯器中而言)將發揮作用。在這種情況下,Java不會進行傳遞計算,因爲cls == B.class,R == B – yshavit

回答

4

雖然在語義上,當您傳遞B.class時,此方法無法返回除Function<A,B>之外的任何其他內容,但編譯器不夠智能以實現此目的。例如,對if條件的錯誤更改足以破壞您的語義。在這種情況下,JLS通常會謹慎對待。

這種情況下,您需要明確轉換爲Function<A,R>才能按照您的意願進行操作。

5

findMapper應該返回Function<A, R>其中R可以是任何東西,不一定B

假設我們用String.class來調用這個方法。現在RString。該函數應該返回一個Function<A, String>,但您返回的是Function<A, B>。編譯器認爲這種可能性,並對你說不。

「但是我在檢查之前檢查了是否RB!」你喊道。那麼,這個檢查是在運行時完成的,編譯器並不在乎。

由於類型擦除,每個通用參數在運行時只是Object。這就是爲什麼你可以把它投到Function<A, B>來解決這個問題。

3

泛型在Java中純粹是編譯時的事情。編譯器在編譯時使用泛型來檢查代碼是否是類型安全的。

但編譯器的檢查有限制。編譯器所做的檢查沒有進行到目的地,編譯器要分析if語句得出結論,在return語句處,R始終等於B

如果它比一個if聲明更復雜怎麼辦?你還希望編譯器分析代碼中的所有可能路徑並得出結論:它是安全的嗎?邏輯可能變得任意複雜。

0

對於我的英語不好,我很抱歉,所以我儘可能多地舉例說明。我希望你能理解我的意思。

讓我們舉一個簡單的例子,其中參數類型是一個對象。

String string(Object value){ 
    return value instanceof String ? value : null; 
} 

上面的例子仍然需要下鑄造以來的value的引用類型StringObject

String string(Object value){ 
    return value instanceof String ? (String)value : null; 
} 

那麼我們擴大與通用參數的例子,你可以通過強制轉換String來解決T類型的有界方法表達式語句賦值的地方。並且如果有界的T不是String類派生自的類型,則在運行時將投射失敗。以上則實例

<T,R> T string(R value){ 
    // the code cast R to T will generate a compile unchecked warnings. 
    return value instanceof String ? (T) value : null; 
} 

// the code is ok on compile stage, but will throw a ClassCastException on runtime. 
Date date= string("bad"); 
// the code is ok both on compile & runtime. 
// because a unbounded generic argument which will reference to Object . 
string("ok"); 

基地可以通過鑄造功能Function<T,R>解決您的代碼:

static <R> Function<A, R> findMapper(Class<R> cls) { 
    if (cls == B.class) { 
     return (Function<A, R>) a2bmapper; 
    } 
    return null; 
} 

我們知道泛型參數RB但仍產生一個未檢查的編譯警告由於編譯器不知道。然後我們可以做下面的事情讓編譯器知道它:

static <R> Function<A, R> findMapper(Class<R> cls) { 
    if (cls == B.class) { 
     return a2bmapper.getClass().cast(a2bmapper); 
    } 
    return null; 
} 
相關問題