Gemäß der Java Language Sepecification , 3. Auflage:
Ich möchte verstehen, warum diese Entscheidung getroffen wurde. Was ist los mit generischen Ausnahmen?
(Soweit ich weiß, handelt es sich bei Generika lediglich um syntaktischen Zucker zur Kompilierungszeit, und sie werden Object
ohnehin in die .class
Dateien übersetzt. Eine effektive Deklaration einer generischen Klasse ist also so, als ob alles darin eine wäre Object
. Bitte korrigieren Sie mich, wenn ich falsch liege .)
java
generics
exception
language-design
Hosam Aly
quelle
quelle
myList.get(i)
, gibt man natürlichget
immer noch ein zurückObject
. Fügt der Compiler eine UmwandlungA
in ein, um einen Teil der Einschränkung zur Laufzeit zu erfassen? Wenn nicht, hat das OP Recht, dass es am Ende zurObject
Laufzeit auf s hinausläuft. (Die Klassendatei enthält sicherlich Metadaten überA
, aber es sind nur Metadaten AFAIK.)Antworten:
Wie bereits erwähnt, sind die Typen nicht überprüfbar, was im folgenden Fall ein Problem darstellt:
Beide
SomeException<Integer>
undSomeException<String>
werden für denselben Typ gelöscht. Die JVM kann die Ausnahmeinstanzen nicht unterscheiden und daher nicht festlegen, welchercatch
Block ausgeführt werden soll.quelle
Hier ist ein einfaches Beispiel für die Verwendung der Ausnahme:
Der Hauptteil der TRy-Anweisung löst die Ausnahme mit einem bestimmten Wert aus, der von der catch-Klausel abgefangen wird.
Im Gegensatz dazu ist die folgende Definition einer neuen Ausnahme verboten, da dadurch ein parametrisierter Typ erstellt wird:
Ein Versuch, die oben genannten zu kompilieren, meldet einen Fehler:
Diese Einschränkung ist sinnvoll, da fast jeder Versuch, eine solche Ausnahme abzufangen, fehlschlagen muss, da der Typ nicht überprüfbar ist. Man könnte erwarten, dass eine typische Verwendung der Ausnahme etwa die folgende ist:
Dies ist nicht zulässig, da der Typ in der catch-Klausel nicht überprüfbar ist. Zum Zeitpunkt dieses Schreibens meldet der Sun-Compiler in einem solchen Fall eine Kaskade von Syntaxfehlern:
Da Ausnahmen nicht parametrisch sein können, ist die Syntax eingeschränkt, sodass der Typ als Bezeichner ohne folgenden Parameter geschrieben werden muss.
quelle
Es ist im Wesentlichen, weil es schlecht entworfen wurde.
Dieses Problem verhindert ein sauberes abstraktes Design, z.
Die Tatsache, dass eine Fangklausel für Generika fehlschlagen würde, ist keine Entschuldigung dafür. Der Compiler kann einfach konkrete generische Typen, die Throwable erweitern, verbieten oder Generika innerhalb von catch-Klauseln nicht zulassen.
quelle
EntityNotFoundException
. Aber das würde die Generika unbrauchbar machen.Generika werden zur Kompilierungszeit auf Typkorrektheit überprüft. Die generischen Typinformationen werden dann in einem Prozess entfernt, der als Typlöschung bezeichnet wird . Zum Beispiel
List<Integer>
wird auf den nicht-generischen Typen umgewandelt werdenList
.Aufgrund der Typlöschung können zur Laufzeit keine Typparameter ermittelt werden.
Nehmen wir an, Sie dürfen so erweitern
Throwable
:Betrachten wir nun den folgenden Code:
Aufgrund der Löschung des Typs weiß die Laufzeit nicht, welcher Catch-Block ausgeführt werden soll.
Daher ist es ein Fehler zur Kompilierungszeit, wenn eine generische Klasse eine direkte oder indirekte Unterklasse von Throwable ist.
Quelle: Probleme beim Löschen des Typs
quelle
Ich würde erwarten, dass es keine Möglichkeit gibt, die Parametrisierung zu garantieren. Betrachten Sie den folgenden Code:
Wie Sie bemerken, ist Parametrisierung nur syntaktischer Zucker. Der Compiler versucht jedoch sicherzustellen, dass die Parametrisierung über alle Verweise auf ein Objekt im Kompilierungsbereich hinweg konsistent bleibt. Im Falle einer Ausnahme kann der Compiler nicht garantieren, dass MyException nur aus einem Bereich ausgelöst wird, den er verarbeitet.
quelle