2010-09-16 102 views
3

有沒有辦法避免以下使用@SuppressWarnings,並保持相同的功能,而不警告「類型安全:未選中從AbstractDO []轉換爲E []」有沒有辦法在此代碼中避免@SuppressWarnings?

public MyClass { 
    ... 
    private Map<Class<? extends AbstractDO>, AbstractDO[]> map; 
    ... 
    private void saveConcreteDOs(AbstractDO[] theEntities) {   
    entityMap.put(theEntities[0].getClass(), theEntities); 
    } 

    @SuppressWarnings("unchecked") 
    protected <E extends AbstractDO> E[] getConcreteDOs(Class<E> theType) { 
    return (E[]) map.get(theType); 
    } 
    ... 
} 

也許提高地圖的聲明?

+0

以防萬一,請忽略NPE和類似的錯誤 - 代碼縮短版,當然 – topchef 2010-09-16 19:27:58

+5

數組和仿製藥不拌勻,更好地利用列表,而不是。 – starblue 2010-09-16 19:37:15

+0

謝謝,這是一個選項。 – topchef 2010-09-16 19:42:15

回答

3

您可以選擇:抑制您知道總是會成功的演員的警告,或者避免警告並驗證演員是否通過了try/catch塊。

只有這兩種選擇。

maybe there is a way to enhance map declaration?

就你而言,我會說你有幾個選擇。

我認爲最好的辦法是到throws ClassCastException條款添加到您的getConcreteDOs方法,讓來電處理無效的投帶來的無效使用的方法 - 假設他們可以得到它來編譯在你extends AbstractDO條款。這具有強制消費者在try/catch塊中包裝調用或者聲明他們自己的throws子句以強制try/catch塊在堆棧上更高的不利副作用。

你可以用一個空的catch塊吞下異常;坦率地說,我更喜歡@SuppressWarning。

或者您可以完全放棄該方法,只處理抽象實體,從而有效地使存儲庫的使用者處理演員陣容。底線:每當您嘗試構建通用存儲庫時,都會遇到這些問題。使用每個實體類型的具體存儲庫模式可能會更好。

+0

也許有一種方法來增強地圖聲明? – topchef 2010-09-16 19:35:53

+1

打敗我吧;我想說,無論何時,當你從父母轉到孩子時,你總是會得到這個警告,因爲編譯器沒有辦法保證這些類型是兼容的。 – 2010-09-16 19:44:43

+0

你的意思是「@SuppressWarnings」註釋會影響運行時行爲? (不管是否投射成功)我是否正確理解你?現在,這是一個消息。 – 2010-09-16 19:51:10

1

你可以通過讓你的類變爲一般的方法來避免未經檢查的轉換。

public class MyClass<E extends AbstractDO> { 

    private Map<Class<? extends AbstractDO>, E[]> map; 

    public void saveConcreteDOs(E[] theEntities) {   
     map.put(theEntities[0].getClass(), theEntities); 
    } 

    public E[] getConcreteDOs(Class<E> theType) { 
     return map.get(theType); 
    } 
} 
+1

我認爲當我用X.class作爲參數調用X []時,其意圖是返回一個X [],因此該映射將包含每個類和相應數組的一個條目。你的建議意味着強制所有的數組子類E ... – helios 2010-09-16 20:20:11

+0

沒錯,helios。 – topchef 2010-09-16 20:30:01

+0

@grigory,那麼如果沒有未經檢查的演員,你將無法脫身。 – 2010-09-16 20:34:50

1

首先,您的代碼不是類型安全的。它可以在運行時拋出類轉換異常。您應該有

 
    private void saveConcreteDOs(AbstractDO[] theEntities) {   
    entityMap.put(theEntities.getClass().getComponentType(), theEntities); 
    } 

您可能在運行時只有同類數組,並且元素[0]與數組元素類型的類型相同。然而,單靠考察這門課是無法知道的。

有了這個更正的代碼,超級智能編譯器可以證明getConcreteDOs()是類型安全的。但是,javac並不那麼聰明。語言規範要求提供警告。

通常,在Java中,無法表示鍵和值之間更復雜的關係。不變量,一個值是一個數組,其組件類型是關鍵字,只保留在你的頭上。

現在,看看這個非數組版本:

private Map<Class<? extends AbstractDO>, AbstractDO> map; 

protected <E extends AbstractDO> E getConcreteDOs(Class<E> theType) 
{ 
    AbstractDO obj = map.get(theType); 
    return theType.cast(obj); 
} 

這有沒有報警,但它的那種作弊。 Class.cast()隱藏了我們的警告,就這些。

它沒有幫助陣列版本,Class<T>中沒有T[] castArray(Object[])。你可以自己製作一種方法,有效地隱藏它的警告。

或者你可以做到這一點,但它確實是不必要的俗氣。如果您知道自己在做什麼,並且您仔細檢查了程序以確保類型安全,請不要擔心未經檢查的警告。

protected <E extends AbstractDO> E[] getConcreteDOs(Class<E[]> arrayType) 
{ 
    AbstractDO[] array = map.get(arrayType.getComponentType()); 
    return arrayType.cast(array); 
} 
... 
X[] array = getConcreteDOs(X[].class); 
+0

我同意避免警告和「@SupressWarnings」本身不是目標。目標是要有清晰,充分和自我解釋的代碼。這就是爲什麼我喜歡你的'如果你知道你在做什麼,並且你仔細檢查了你的程序以確保類型的安全,不要害怕不加控制的警告。 – topchef 2010-09-17 04:25:41

+0

關於類型安全的第一個注意事項對我而言並不清楚。 'TheEntities [0] .getClass()'可能不會轉換爲'Class <?擴展AbstractDO>'? – topchef 2010-09-17 04:28:59

+0

@grigory說B是A的子類,如果'array = new A [] {new B(),new A()}',你的代碼會認爲該數組是'B []' – irreputable 2010-09-17 14:46:06

相關問題