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.
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.
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:
Es handelt sich also nicht um ein Enum
spezifisches Problem, aber möglicherweise liegt es an den involvierten rekursiven Typen.
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.
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.
Tags und Links java java-8 generics compiler-errors java-7