2016-02-12 17 views
7

Zaczęliśmy coraz skompilować błędy w kodzie, które używane rodzajowych i że z powodzeniem skompilowany pod Java 6. Oto proste klasy do reprodukcji:błąd ogólny czas kompilacji Java migracji z Java 6 do 7 lub 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 
    } 
} 

Wynikowy błąd:

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

Czy ktoś ma jakieś pomysły?

+0

Niestety, nie wspominając, że błędy kompilacji zdarzyć w Java 7 i 8, ale nie w 6 ... –

+0

dziwne, a ja dostać ten błąd kompilacji używając jdk1.7.0_13 z wiersza polecenia, to kod kompiluje grzywny w środowisku Zaćmienie, używając tego samego kompilatora (sprawdź, czy "zainstalowany JRE" wskazuje tę samą ścieżkę, i czy poziom zgodności wynosi 1.7, i używając tego jdk). – azurefrog

+0

Mam dokładnie to samo - Eclipse skompilował to z zestawem 1.8 bez błędu. Bardzo dziwne ... –

Odpowiedz

2

Dzieje się tak, ponieważ Foobar bez żadnych parametrów typu jest surowy typ. Surowe typy nie mają ogólnych właściwości, więc w tym przypadku surowy typ Foobar rozszerza się o Bar, który rozszerza surowy typ Foo. Surowe typy wykorzystują górną granicę swoich parametrów, ponieważ są kompilowane w ten sposób po usunięciu, a kompilator nie ma parametrów typu, aby bezpiecznie wstawić rzuty.

W przypadku Foo ta górna granica to Object. Powoduje to, że Foo.get() zwraca Object, więc Bar.get() zwraca Object, a więc Foobar.get() również zwraca Object. Oczywiście kompilator nie rzuci Object do Long bez wyraźnego rzutowania.

W przeciwieństwie do tego sparametryzowany typ Foobar<N> rozszerza się o Bar, który rozszerza sparametryzowany typ Foo<Long>. Kompilator może teraz używać rodzajowych, więc widzi, że Foo<T>.get() ma typ T, że Foo<Long>.get() ma typ Long, że Bar.get() ma typ Long, i wreszcie, że Foobar<N>.get() ma typ Long również.

To oznacza, że ​​należy zadeklarować foobar jak pokazano:

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

To nie ma znaczenia, jaki parametr typ foobar jest, tak długo jak jest on obecny. Może nawet być symbolem wieloznacznym ?.

+2

Ale dlaczego typ surowy działa w 1.6? Nie jestem świadomy żadnych zmian w 1.7 do generycznych (poza wnioskami typu) – radoh

+0

@radoh Myślę, że właśnie dokonali sprawdzenia typu surowszego w 7. Typy nie powinny istnieć we współczesnym kodzie, są tylko tam dla kompatybilności, dla typów które zostały zaktualizowane za pomocą generycznych, mimo że kod wywołujący nie był. Nie jestem jednak pewien, najlepiej sprawdzić informacje o wydaniu Oracle. – HTNW

+0

Dzięki za wyjaśnienie, Osobiście uważam, że sposób Java 6 był bardziej intuicyjny, a zmiany wymagały, aby średni kod był dłuższy. Typowa instancja typu zdefiniowana bez parametru powinna być traktowana jako parametr podstawowy, w tym przypadku sam Foobar powinien być traktowany identycznie jak Foobar ... –

Powiązane problemy