2013-02-13 61 views
5

我已經在我的項目,看起來像這樣的代碼:這是鑄造在我的通用方法安全嗎?

public interface Bar<T extends Foo<?>> { 
//... 
} 

public class MyFoo implements Foo<String> { 
    private List<Bar<Foo<String>> barFoo = ... 

    public <U extends Foo<String>> boolean addBar(Bar<? extends U> b) { 
     barFoo.add((Bar<Foo<String>>) b); //safe cast? 
    } 

} 

Eclipse中給出了在addBar投,中投是不安全的警告。然而,我是否正確地假設演員陣容不會因爲我對類型參數的限制而拋出,因此演員陣容確實安全?

回答

6

不一般。

假設Bar有一個方法void get(T value),並且有的Foo<String>MyFooYourFoo兩個實現。現在假設來電者呼叫addBar的值爲Bar<MyFoo>。這工作:當U = Foo<String>,我們有Bar<MyFoo>Bar<? extends U>的子類型。現在我們將該值轉換爲Bar<Foo<String>>

現在,如果Bar沒有接受T作爲參數的方法,那就沒有問題了。但是,假設它有一個方法void process(T value)。我們調用的實現有T = MyFoo,所以它只有一個process(MyFoo value)方法。但是,一旦我們將其轉換爲Bar<Foo<String>>,我們可以用YourFoo來代替它。這是非法的。

刺在黑暗中,但我懷疑你真正想要做的是宣佈barFooList<? extends Bar<? extends Foo<String>>

+0

優秀的答案。謝謝! – 2013-02-13 23:06:26

+0

@DongieAgnir你可能很好'List >'和'public boolean addBar(Bar <?extends Foo >)' – irreputable 2013-02-13 23:28:14

2

這不是一個安全的演員。 Eclipse是正確的。

想象一下,你有一個類MyFoo擴展Foo和你在一個Bar<MyFoo<String>>現在有一些方法傳入BarmyMethod(Foo x)簽名時只有myMethod(MyFoo x)簽名被編譯,因此該方法查找會失敗。

+0

你不能有一個繼承String的類,因爲它是final的,對嗎? – 2013-02-13 22:02:46

+1

@CyrilleKarmann:梅爾尼克爾森寫了_Imagine ..._ – jlordo 2013-02-13 22:06:35

+0

這是一個很好的觀點,並且是字符串如何保證不變性的一部分。如果您使用MyFoo擴展Foo,則同樣的邏輯適用,並且我們假設Foo不是最終的。 – 2013-02-13 22:07:00

0

演員陣容安全的,因爲雖然U延伸Foo<String>,它是(一定),其Bar<U>延伸Bar<Foo<String>>的情況。實際上,Bar<U>只有在Bar<Foo<String>>是相同的情況下才會擴展,即當UFoo<String>時。

從直觀上看,(例如)List<String>應該是List<Object>的子類型,但這不是泛型工作的方式。 List<String>List<? extends Object>的亞型,但它是而不是List<Object>的亞型。 (這可能更有意義考慮一個例子,如Comparable<T>Comparable<String>表示「可以與任何String比較,而Comparable<Object>意味着」可以與任何Object比較「。應該清楚,Comparable<String>不應該是Comparable<Object>的子類型。

[&hellip;]中投不會拋出[&hellip;],因此劇組確實是安全的

我想你誤解了警告的性質?Eclipse會警告你,即使它應該是,這個演員陣容也不會拋出,而這實際上是爲什麼這是不安全的。例如,此代碼:

final Object o = Integer.valueOf(7); 
final String s = (String) o; 

是完全安全的,因爲投射會拋出異常。但是這個代碼:

final List<?> wildcardList = new ArrayList<Integer>(Integer.valueOf(7)); 
final List<String> stringList = (List<String>) wildcardList; 

不安全,因爲運行時沒有檢查投(由於擦除)的方式,所以不會拋出異常,即使它是錯的:stringList現在是一個List<String>,其第一個元素是Integer。 (會發生什麼,在稍後的某個時刻,當你嘗試使用該元素時,你可以得到一個自發的ClassCastException)。