2011-12-26 7 views
13

Poniższy kodDlaczego ogólna obsada listy <? extends Set ..> na listę <Set..> się uda na Sun JDK 6, ale nie kompiluje się w Oracle JDK 7?

class GenericCompilationFailureDemo { 
    List<? extends GenericCompilationFailureDemo> newList() { 
     return new ArrayList<GenericCompilationFailureDemo>(); 
    }; 

    void useList() { 
     List<GenericCompilationFailureDemo> list = 
      (List<GenericCompilationFailureDemo>) newList(); 
    } 

    List<? extends Set<GenericCompilationFailureDemo>> newListOfSpecificSets() { 
     return new ArrayList<Set<GenericCompilationFailureDemo>>(); 
    }; 

    void useListOfSpecificSets() { 
     List<Set<GenericCompilationFailureDemo>> listOfSpecificSets = 
      (List<Set<GenericCompilationFailureDemo>>) newListOfSpecificSets(); 
    } 

    List<? extends Set<? extends GenericCompilationFailureDemo>> newListOfSets() { 
     return new ArrayList<Set<? extends GenericCompilationFailureDemo>>(); 
    }; 

    void useListOfSet() { 
     List<Set<? extends GenericCompilationFailureDemo>> listOfSets = 
      (List<Set<? extends GenericCompilationFailureDemo>>) newListOfSets(); 
    } 
} 

kompiluje pod Sun JDK 1.6.0_20 (64-bit Windows Vista, ale nie sądzę, że czyni żadnej różnicy), ale powoduje następujące niepowodzenie kompilacji pod Oracle JDK 1.7.0_01 (ta sama platforma):

[ERROR] src\main\java\GenericCompilationFailureDemo.java:[56,78] error: inconvertible types 

Zauważ, że pierwszy dwa „rozciąga się do określonego typu” rzuca w useList i useListOfSpecificSets zarówno pod 1.7.0_01 jeszcze odnieść sukces, więc wydaje się, że to ma coś wspólnego z "podwójny rodzajowy się rozszerza".

Jakieś pomysły, które mogły się zmienić między 6 a 7, i czy zaobserwowane zachowanie jest zgodne ze specyfikacją lub błędem?

edytowane w odpowiedzi na komentarz Sanjay za:

@Sanjay: Aha, ciekawe! Tutaj wyjście z java -version:

java version "1.7.0_01" 
Java(TM) SE Runtime Environment (build 1.7.0_01-b08) 
Java HotSpot(TM) 64-Bit Server VM (build 21.1-b02, mixed mode) 

I tu wynikiem javac GenericCompilationFailureDemo.java (ten sam kod jak wyżej z wypowiedzi na przywóz List, ArrayList set):

GenericCompilationFailureDemo.java:30: error: inconvertible types 
      (List<Set<? extends GenericCompilationFailureDemo>>) newListOfSets() 
; 
                      ^
    required: List<Set<? extends GenericCompilationFailureDemo>> 
    found: List<CAP#1> 
    where CAP#1 is a fresh type-variable: 
    CAP#1 extends Set<? extends GenericCompilationFailureDemo> from capture of ? 
extends Set<? extends GenericCompilationFailureDemo> 
Note: GenericCompilationFailureDemo.java uses unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 
1 error 
+1

Na co warto, to kompiluje kod na moim JDK 7. Można zaksięgować całą moc 'java -version' polecenia wraz z„Build " strunowy? –

+0

proszę wkleić dokładne błędy kompilacji + sugestie sanjaya. * Wierzę, że generics mają być nieco prostsze w java 7 * w niektórych przypadkach ... może znalazłeś przypadek rogu, gdzie starsza, złożona, składnia JDK 6 łamie nowy kompilator. – jayunit100

+0

@Sanjay: aha, ciekawe! Zobacz edytowane pytanie odpowiedzi na komentarze –

Odpowiedz

7

To widocznie błąd javac7. Powinno być dozwolone na zasadach konwersji odlewania [1]

Jedną z zasad pozwala konwersję odniesienia zwężenie ... następnie niesprawdzony konwersji

Casting List<A> => List<B> jest dozwolone przez tę regułę

List<A> => List // narrowing reference conversion 
List => List<B> // unchecked conversion 

To jednak nie wszystko; specyfikacja zawiera dalsze zasady zakazu odlewania, takie jak , ponieważ są to o wyraźnie różnych parametrach typów. Nie ma obiektu należącego do obu typów w tym samym czasie, więc kompilator uważa, że ​​lepiej odrzucić ten oczywisty błąd programowania. (Można ominąć to jawnie List<String>=>List=>List<Integer>)

Ostatnia reguła tutaj nie ma zastosowania; więc wygląda jak błąd javac7.

Dlaczego ostatnia reguła nie ma zastosowania: dlatego przesyłamy List<? extends A> do List<A>. Tutaj konwersja przechwytywania jest stosowana do List<? extends A> [2], więc faktycznie odlewane jest List<T> do List<A>, gdzie T jest zmienną nowego typu z górną granicą A.

Pytanie brzmi, czy List<T> i List<A>znacznie różniących się parametrami typów. Rozumiem, że jest to fałsz (musi być fałszywy, aby twoje pierwsze dwa przykłady zostały skompilowane). Ponieważ T jest zmienną typu, może przyjmować wartość, aby List<T> i List<A> był tym samym parametryzowanym typem (tj. Gdy T=A). To rozumowanie powinno działać dla każdego typu A.

[1] http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5

[2] http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#341306

+0

_Możesz ominąć ją przez jawnie Listę => Lista => Lista ) _ Weryfikacja tak naprawdę - ale "hackowanie leków generycznych" nie było czymś, co naprawdę chciałem popełnić ;-) Dzięki za wyjaśnienie! Czy jest ktoś w Oracle, z którym chciałbyś się skontaktować (np. Z listą kompilatorów itd.), Aby sprawdzić, czy warto zgłosić błąd? –

+0

lista kompilatorów powinna być dobra. – irreputable

+1

Właśnie napisałem do kompilatora. Ciekawe, jakie odpowiedzi otrzymamy ;-) –

Powiązane problemy