Warum kompiliert das in Java7 und nicht in Java8?

8

Generika sind schwierig. Und es sieht so aus, als ob sie in verschiedenen Java-Versionen unterschiedlich behandelt werden.

Dieser Code kompiliert erfolgreich in Java 7 und kann nicht mit Java 8 kompiliert werden.

%Vor%

Hier ist eine Fehlermeldung von Java 8. Ich habe diese verwendet, um sie zu kompilieren: Ссылка

%Vor%

Die Frage bezieht sich auf den Unterschied zwischen den Versionen des Java-Compilers.

    
Timothy Basanov 09.10.2014, 01:44
quelle

4 Antworten

12

Der Hauptunterschied zwischen Java 7 und Java 8 ist die Zieltyp-Inferenz. Während Java 7 nur die Parameter eines Methodenaufrufs zur Bestimmung der Typargumente berücksichtigt, verwendet Java 8 den Zieltyp eines Ausdrucks, dh den Parametertyp im Falle eines verschachtelten Methodenaufrufs, den Typ der Variablen, die initialisiert oder zugewiesen wird to oder der Rückgabetyp der Methode im Fall einer return -Anweisung.

z. Beim Schreiben von List<Number> list=Arrays.asList(1, 2, 3, 4); wird Java 7 den Typ List<Integer> für die rechte Seite ableiten, indem er die Argumente der Methode betrachtet und einen Fehler generiert, während Java 8 den Zieltyp List<Number> verwendet, um die Abhängigkeit der Methodenargumente abzuleiten müssen Instanzen von Number sein, was der Fall ist. Daher ist es in Java 8 legal.

Wenn Sie an den formalen Details interessiert sind, können Sie das "Java Language Specification, Kapitel 18. Type Inference ", insbesondere § 18.5.2. Invocation Type Inference , das ist jedoch nicht einfach zu lesen ...

Was passiert also, wenn Sie Enum foo = null; tryCompile(EnumSet.of(foo)); sagen?

In Java 7 wird der Typ des Ausdrucks EnumSet.of(foo) abgeleitet, indem der Typ des Arguments foo betrachtet wird, welches der rohe Typ Enum ist. Daher wird eine ungeprüfte Operation ausgeführt und der Ergebnistyp ist der Rohtyp EnumSet . Dieser Typ implementiert den Rohtyp Iterable und kann daher an tryCompile übergeben werden, wodurch eine weitere ungeprüfte Operation entsteht.

In Java 8 ist der Zieltyp von EnumSet.of(foo) der Typ des ersten Parameters von tryCompile , der Iterable<C extends Enum<C> & Another> ist. Ohne in Details zu gehen, wird in Java 7 EnumSet.of als roher Typ behandelt Aufruf, da es ein Raw-Type-Argument hat, wird es in Java 8 als generischer Aufruf behandelt, da es einen generischen Zieltyp hat. Wird der Compiler als generischer Aufruf behandelt, kommt er zu dem Schluss, dass der gefundene Typ ( Enum ) nicht mit dem erforderlichen Typ C extends Enum<C> & Another kompatibel ist. Während Sie den unformatierten Typ Enum mit einer unmarkierten Warnung dem C extends Enum<C> zuweisen könnten, wird er als inkompatibel mit Another (ohne Typumwandlung) betrachtet.

Sie können tatsächlich einen solchen Cast einfügen:

%Vor%

Dies kompiliert natürlich nicht ohne eine ungeprüfte Warnung aufgrund der Zuordnung von Enum zu C extends Enum<C> .

Sie können die Zieltypbeziehung auch auflösen, so dass die gleichen Schritte wie in Java 7 ausgeführt werden:

%Vor%

Hier werden unformatierte Typen in den drei Zeilen verwendet, so dass dies mit ungeprüften Warnungen und der gleichen Ignoranz bezüglich der Einschränkung implements Another wie in Java 7 kompiliert wird.

    
Holger 09.10.2014, 18:32
quelle
2

Die Type-Inferenz-Engine in Java 8 wurde verbessert, und (ich nehme an) kann nun feststellen, dass der C -Typ Another nicht erweitert.

In Java 7 konnte oder konnte das Typ-Inferenzsystem nicht feststellen, dass der Another -Typ fehlte, und gab dem Programmierer den Vorteil des Zweifels (zur Kompilierungszeit).

Sie zahlen immer noch für die Überschreitung zur Laufzeit, wenn Sie zur Laufzeit in Java 7 Methoden auf der Schnittstelle Another aufrufen.

Zum Beispiel dieser Code:

%Vor%

Erzeugt diesen Fehler zur Laufzeit:

%Vor%

Obwohl der Java 7-Compiler den Code kompiliert, gibt er immer noch Warnungen über unformatierte Typen und ungeprüfte Aufrufe ab, die Sie darauf hinweisen sollten, dass etwas nicht stimmt.

Hier ist ein ziemlich unkompliziertes Beispiel, das keine Aufzählung verwendet, sondern der Definition von Enum nachempfunden ist, die das gleiche Problem aufweist. Kompiliert mit Warnungen in Java 7, aber nicht in Java 8:

%Vor%

Es handelt sich also nicht um ein Enum spezifisches Problem, aber möglicherweise liegt es an den involvierten rekursiven Typen.

    
msandiford 09.10.2014 02:26
quelle
0

Sieht für mich wie ein korrekter Fehler aus:

%Vor%

EnumSet.of(foo) hat den Typ EnumSet<Enum> , der nicht mit C extends Enum<C> & Another kompatibel ist, aus dem gleichen Grund, weil Set<Enum> nicht mit Set<? extends Enum> kompatibel ist, da Java Generics invariant sind.

    
Daniel Pryden 09.10.2014 02:14
quelle
-1

dies kompiliert sich für mich in Eclipse Standard / SDK Version: Luna Release (4.4.0) Build ID: 20140612-0600 mit dem Eclipse JDT (Java Development Tools) Patch mit Java 8 Unterstützung (für Kepler SR2) 1.0.0 .v20140317-1956 org.eclipse.jdt.java8patch.feature.group Eclipse.org installiert.

Ich bekomme ein paar Warnungen (roher Typ auf foo und Unchecked Aufruf auf tryCompile.

    
Ray Tayek 09.10.2014 03:09
quelle