2016-02-12 121 views
7

我們已經開始收到編譯所使用泛型的代碼錯誤和Java的6下成功編譯Java的泛型編譯時錯誤這裏有一個簡單的類重現:遷移從Java 6到7或8

class Test { 
    static class Foo<T> { 
      T t; 
      Foo(T t) { this.t = t; } 
      T get() { return t; } 
    } 

    static class Bar extends Foo<Long> { 
      Bar(Long t) { super(t); } 
    } 

    static class Foobar<N extends Number> extends Bar { 
      Foobar() { super(5L); } 
    } 

    public static void main(String[] args) { 
      Bar bar = new Bar(0L); 
      Long b = bar.get();    // This works 
      Foobar foobar = new Foobar(); 
      Long fb = foobar.get(); // This generates a compile time error 
    } 
} 

由此產生的錯誤是:

Test.java:26: error: incompatible types: Object cannot be converted to Long 
      Long fb = foobar.get(); // This generates a compile time error 

有沒有人有任何想法?

+0

對不起,沒有提到編譯錯誤發生在Java 7和8中,但不是在6 ... –

+0

奇怪的是,雖然我從命令行使用jdk1.7.0_13得到這個編譯錯誤,但這段代碼編譯得很好在eclipse中,使用相同的編譯器(雙重檢查「已安裝的JRE」指向相同的路徑,合規性級別爲1.7,並使用該jdk)。 – azurefrog

+0

我得到了完全一樣的 - Eclipse編譯1.8集沒有錯誤。很奇怪...... –

回答

2

這是因爲Foobar沒有任何類型參數是原始類型。原始類型沒有通用能力,因此在這種情況下,原始類型Foobar延伸了Bar,這擴展了原始類型Foo。原始類型使用其參數的上限,因爲它們在擦除之後以這種方式編譯,並且編譯器沒有類型參數來安全地插入強制轉換。

Foo的情況下,該上限爲Object。這導致Foo.get()返回Object,所以Bar.get()返回Object,所以Foobar.get()也返回Object以及。很明顯,編譯器不會將Object轉換爲Long而不顯式轉換。

相反,參數化類型Foobar<N>延伸Bar,它擴展了參數化類型Foo<Long>。編譯器現在可以使用仿製藥,所以它看到Foo<T>.get()的類型爲T,即Foo<Long>.get()具有類型Long,即Bar.get()具有類型Long,最後是Foobar<N>.get()具有類型Long爲好。

這意味着如圖所示,你應該申報foobar

Foobar<...> foobar = new Foobar<...>(); 

不要緊的foobar類型參數是什麼,就像只要它存在。它甚至可以是通配符?

+2

但是,爲什麼原始類型在1.6中工作?我不知道1.7中泛型的任何變化(除了類型推斷) – radoh

+0

@radoh我認爲他們只是在7中進行了更嚴格的類型檢查。原始類型不應該存在於現代代碼中,它們僅用於兼容性,類型即使調用代碼不是調用泛型更新。儘管並不確定,但最好只檢查Oracle的發行說明。 – HTNW

+0

感謝您的解釋,就我個人而言,我認爲Java 6的方式更直觀,所需的更改意味着代碼必須更長時間。沒有參數定義的泛型類型實例應該被視爲基本參數,在這種情況下Foobar本身應該被視爲Foobar ... –