Nehmen wir an, ich hatte eine Methode wie folgt:
%Vor% Zugegeben, nicht die beste Signatur der Welt, aber immer noch vollkommen legal. Was würde passieren, wenn ich ein List<String>
an diese Methode übergeben würde? Gemäß der Signatur wird ein List<? extends String>
zurückgegeben. Wenn Java diesen Typ nicht zulässt, wäre es unmöglich, diese Methode für List<String>
zu verwenden (oder zumindest wäre es unmöglich, den Rückgabewert zu verwenden).
Zweitens ist die extends
-Syntax in diesem Fall immer noch nützlich, da List<String>
und List<? extends String>
unterschiedliche Einschränkungen haben - speziell können Sie nichts als null
literal zu List<? extends String>
hinzufügen. Ich werde manchmal ? extends
verwenden, um zu signalisieren, dass eine Sammlung schreibgeschützt ist (da nur T
s übergeben werden können, sind null
) und ? super
, um schreibgeschützt zu bedeuten (da du nur erhalten kannst aus T
s als Object
). Dies ist nicht völlig narrensicher (Sie können immer noch remove-Methoden aufrufen, in null
s übergeben, downcast, etc.), aber dient als eine sanfte Erinnerung an, wie die Sammlung wahrscheinlich verwendet werden soll.
Der Compiler nimmt diese Tatsache nicht wirklich zur Kenntnis, weil das nicht wichtig ist. String
s sind weiterhin in der Liste erlaubt, und im Endprodukt wird die Möglichkeit, dass% ce_de% erweitert wird, nicht gefunden. Nach Löschung kommt es folgendermaßen heraus:
Wie Sie sehen, gibt es jetzt keine Vorschläge für eine Klasse, die String
erweitert. Wenn Sie eine Klasse erstellen, die String
erweitert, ist das selbst ein Kompilierungsfehler. Es gibt keine Notwendigkeit für Javac, sich darüber Sorgen zu machen.
Das Typsystem berücksichtigt List<String>
und List<? extends String>
nicht, obwohl String
zum Zeitpunkt des Kompilierens keine anderen Subtypen als sich selbst hat. Daher muss jedes Objekt, das ein List<? extends String>
ist, auch ein% sein. co_de%.
Eine Erklärung ist, dass List<String>
nicht endgültig ist - es ist in Ordnung, final
aus einer Klasse zu entfernen, und nichts sollte brechen: Ссылка
Es ist nicht selbstverständlich, dass das Typsystem final
berücksichtigt; Zum Beispiel können wir final
nicht auf String
umwandeln, weil der Compiler feststellt, dass wenn ein Objekt Runnable
ist, es keine unbekannte Unterklasse sein kann, die String
implementiert.
Wenn wir möchten, dass Generika auch solche Schlüsse ziehen und daraus schließen, dass Runnable
und List<String>
gleichwertig sind, werden die Schreibregeln noch komplizierter.