2010-01-11 117 views
2

調用此方法:Java泛型:誰是正確的,javac或Eclipse編譯?

public static @Nonnull <TV, TG extends TV> Maybe<TV> something(final @Nonnull TG value) { 
    return new Maybe<TV>(value); 
} 

這樣的:

public @Nonnull Maybe<Foo> visit() { 
    return Maybe.something(new BarExtendsFoo()); 
} 

編譯在Eclipse就好了,但javac的給出了一個 「不相容類型的」 警告:

found : BarExtendsFoo 

要求:富

+2

工作示例而不非標註釋和缺課將使它更容易爲人們提供幫助。 – 2010-01-11 09:42:39

+0

我有一個簡單的問題......編譯器如何知道你想在調用中返回的實際類型:'Maybe.something(new BarExtendsFoo())'? – 2010-01-11 09:48:04

+0

爲什麼不是 public @Nonnull也許<?延伸Foo> visit(){...} ? – 2010-01-11 09:49:27

回答

2

我不明白爲什麼javac沒有推斷出c orrect類型,
但你可以幫助編譯器通過在

public @Nonnull Maybe<Foo> visit() { 
    return Maybe.<Foo, BarExtendsFoo>something(new BarExtendsFoo()); 
} 
+1

這確實解決了這個問題,儘管我希望避免使用something()方法的複雜簽名來顯式打字。 我現在它簡化爲這一點,因爲我需要提供反正類型: 也許東西(最終TV值) 感謝所有這些提示。 – tbk 2010-01-11 15:25:53

5

供應類型有明顯的javac和Eclipse之間存在一些差異。但是,這裏的主要觀點是javac在發佈錯誤時是正確的。最終,您的代碼會將一個Maybe <BarExtendsFoo>轉換爲有風險的Maybe <Foo>。

這裏的訪問()方法的重寫:

public static <TV, TG extends TV> Maybe<TV> something(final TG value) { 
    return new Maybe<TV>(value); 
    } 

    public static class Foo { } 

    public static class BarExtendsFoo extends Foo { } 

    public Maybe<Foo> visit() { 
    Maybe<BarExtendsFoo> maybeBar = something(new BarExtendsFoo()); 
    Maybe<Foo> maybeFoo = maybeBar; // <-- Compiler error here 

    return maybeFoo;  
    } 

這改寫實際上等同於你的代碼,但它明確地說明你想從也許<使BarExtendsFoo >到也許<富分配>。這是有風險的。事實上,我的Eclipse編譯器在作業行上發佈了一個錯誤。下面是一段代碼來利用這個風險來存儲也許<字符串>對象內部的整數:

public static void bomb() { 
    Maybe<String> maybeString = new Maybe<String>(""); 

    // Use casts to make the compiler OK the assignment 
    Maybe<Object> maybeObject = (Maybe<Object>) ((Object) maybeString); 
    maybeObject.set(new Integer(5)); 

    String s = maybeString.get(); // Runtime error (classCastException): 
            // java.lang.Integer incompatible with 
            // java.lang.String 
    } 
+0

從Maybe 轉換爲Maybe 並不是我所期望的。 something()方法應該返回'Maybe ',所以'TV'應該是Foo而不是BarExtendsFoo。重寫僅對javac有效(相同)。 Eclipse接口使用期望的返回值來推斷(正確?)'TV'類型,以便something()創建Maybe 。 – 2010-01-11 13:38:43

0

兩點意見:

一個。正如你在其中一個註釋中提到的那樣,something()的簽名中的TG類型參數根本就沒有必要,因爲在該方法中沒有特定於子類TG的特性。

b。最簡單的解決方法是通過將新創建的對象明確分配給變量(通常這是一種很好的做法),幫助編譯器瞭解您使用的是哪種類型。它現在更清楚的編譯器和人都讀者你想如何調用該方法:

public @Nonnull Maybe<Foo> visit() { 
    final Foo bar = new BarExtendsFoo(); 
    return Maybe.something(bar); 
}