Ich weiß nicht, warum das kompilieren. Auf der anderen Seite kann ich erklären, wie Sie die Compile-Time-Checks voll ausnutzen können.
Also, newList()
ist eine generische Methode, es hat einen Typ Parameter. Wenn Sie diesen Parameter angeben, dann wird der Compiler, dass Sie überprüfen:
Fails zu kompilieren:
String s = Main.<String>newList(); // this doesn't compile anymore
System.out.println(s);
Pässe bei der Kompilierung:
List<Integer> l = Main.<ArrayList<Integer>>newList(); // this compiles and works well
System.out.println(l);
Angeben thetype Parameter
T Die Typparameter bieten nur die Überprüfung der Kompilierzeit. Dies ist von Entwurf, Java verwendet type erasure für generische Typen. Um den Compiler für Sie arbeiten zu lassen, müssen Sie diese Typen im Code angeben.
Type-Parameter auf Instanz-creation
Der häufigste Fall sind das Muster für eine Objektinstanz angeben. I.e. für Listen:
List<String> list = new ArrayList<>();
Hier können wir sehen, dass List<String>
den Typ für die Listeneinträge angibt. Auf der anderen Seite, neue ArrayList<>()
nicht. Es verwendet stattdessen die diamond operator. I.e. der Java-Compiler infers der Typ basierend auf der Deklaration.
Implizite Typparameter bei Methodenaufruf
Wenn Sie eine statische Methode aufrufen, dann müssen Sie den Typ in einer anderen Art und Weise angeben. Manchmal kann man es als Parameter angeben:
public static <T extends Number> T max(T n1, T n2) {
if (n1.doubleValue() < n2.doubleValue()) {
return n2;
}
return n1;
}
Die Sie es wie folgt verwenden können:
int max = max(3, 4); // implicit param type: Integer
Oder wie folgt aus:
double max2 = max(3.0, 4.0); // implicit param type: Double
Explizite Typparameter bei Methodenaufruf:
Sagen Sie zum Beispiel, das ist, wie Sie kann eine typsichere leere Liste erstellen:
List<Integer> noIntegers = Collections.<Integer>emptyList();
Der Typ-Parameter <Integer>
emptyList()
an die Methode übergeben wird. Die einzige Einschränkung besteht darin, dass Sie auch die Klasse angeben müssen. I.e. Sie können dies nicht tun:
import static java.util.Collections.emptyList;
...
List<Integer> noIntegers = <Integer>emptyList(); // this won't compile
Runtime Typ Token
Wenn keine dieser Tricks, die Sie helfen können, dann können Sie eine runtime type token angeben. I.e. Sie stellen eine Klasse als Parameter bereit. Ein gängiges Beispiel ist die EnumMap:
private static enum Letters {A, B, C}; // dummy enum
...
public static void main(String[] args) {
Map<Letters, Integer> map = new EnumMap<>(Letters.class);
}
In Verbindung stehende http://stackoverflow.com/questions/36402646/generic-return-type-upper-bound-interface-vs-class-surfishly-valid-code – Tunaki
Der Grund für das Update einen Unterschied machen ist das erste Version kann funktionieren, wenn es einen Typ gibt, der die Bedingungen erfüllt (T extends List & T extends String) [dh es ist eine existenzielle Quantifizierung], während die zweite Version nur funktionieren kann, wenn alle möglichen Typen T, die mit der Deklaration in der Klasse übereinstimmen, auch String [d. h. es ist eine universelle Quantifizierung]. –