Ich habe das SCJP 6-Buch von Kathe sierra durchgesehen und bin auf diese Erklärungen gestoßen, Ausnahmen in überschriebener Methode zu werfen. Ich habe es nicht verstanden. Kann mir jemand das erklären?
Die überschreibende Methode darf KEINE geprüften Ausnahmen auslösen, die neu oder umfassender sind als die von der überschriebenen Methode deklarierten. Beispielsweise kann eine Methode, die eine FileNotFoundException deklariert, nicht von einer Methode überschrieben werden, die eine SQLException, Exception oder eine andere Nicht-Laufzeit-Ausnahme deklariert, es sei denn, es handelt sich um eine Unterklasse von FileNotFoundException.
Antworten:
Wenn eine Methode deklariert, eine bestimmte Ausnahme auszulösen, kann die überschreibende Methode in einer Unterklasse nur deklarieren, dass diese Ausnahme oder ihre Unterklasse ausgelöst wird. Beispielsweise:
SocketException extends IOException
, aberSQLException
nicht.Dies liegt am Polymorphismus:
Wenn Sie
B
sich für einen Wurf entschieden hätten,SQLException
könnte der Compiler Sie nicht zwingen, ihn abzufangen, da Sie sichB
durch seine Oberklasse auf die Instanz von beziehen -A
. Auf der anderen Seite wird jede Unterklasse vonIOException
durch Klauseln (catch oder throw) behandelt, die diese behandelnIOException
Die Regel, die Sie benötigen, um Objekte nach ihrer Oberklasse referenzieren zu können, ist das Liskov-Substitutionsprinzip.
Da ungeprüfte Ausnahmen überall ausgelöst werden können, unterliegen sie nicht dieser Regel. Sie können der Throws-Klausel eine ungeprüfte Ausnahme als Dokumentationsform hinzufügen, wenn Sie möchten, aber der Compiler erzwingt nichts dagegen.
quelle
@Override public void foo() {...}
ist legal.Die überschreibende Methode KANN jede ungeprüfte (Laufzeit-) Ausnahme auslösen, unabhängig davon, ob die überschriebene Methode die Ausnahme deklariert
Beispiel:
quelle
Meiner Meinung nach ist es ein Fehler im Java-Syntaxdesign. Polymorphismus sollte die Verwendung der Ausnahmebehandlung nicht einschränken. Tatsächlich tun es andere Computersprachen nicht (C #).
Darüber hinaus wird eine Methode in einer spezielleren Unterklasse überschrieben, so dass sie komplexer ist und aus diesem Grund wahrscheinlicher neue Ausnahmen auslöst.
quelle
Ich gebe diese Antwort hier auf die alte Frage, da keine Antworten darauf hinweisen, dass die überschreibende Methode hier nichts mehr werfen kann, was die überschreibende Methode werfen kann:
1) werfen Sie die gleiche Ausnahme
2) Wirf eine Unterklasse der ausgelösten Ausnahme der Overriden-Methode
3) nichts werfen.
4) RuntimeExceptions in Würfen sind nicht erforderlich.
Es kann RuntimeExceptions in Würfen geben oder nicht, der Compiler wird sich nicht darüber beschweren. RuntimeExceptions sind keine geprüften Ausnahmen. Es sind nur aktivierte Ausnahmen erforderlich, um in Würfen zu erscheinen, wenn sie nicht gefangen werden.
quelle
Um dies zu veranschaulichen, betrachten Sie:
Angenommen, Sie schreiben dann:
Dies führt zu einem Kompilierungsfehler, da r.close () eine IOException auslöst, die breiter als FileNotFoundException ist.
Um dies zu beheben, wenn Sie schreiben:
Sie erhalten einen anderen Kompilierungsfehler, weil Sie die Operation perform (...) implementieren, aber eine Ausnahme auslösen, die nicht in der Definition der Methode durch die Schnittstelle enthalten ist.
Warum ist das wichtig? Nun, ein Verbraucher der Schnittstelle kann haben:
Wenn die IOException ausgelöst werden durfte, ist der Code des Clients nicht mehr korrekt.
Beachten Sie, dass Sie diese Art von Problem vermeiden können, wenn Sie nicht aktivierte Ausnahmen verwenden. (Ich schlage nicht vor, dass Sie es tun oder nicht, das ist eine philosophische Frage)
quelle
Lassen Sie uns ein Interview Frage nehmen. Es gibt eine Methode, die NullPointerException in der Oberklasse auslöst. Können wir es mit einer Methode überschreiben, die RuntimeException auslöst?
Um diese Frage zu beantworten, teilen Sie uns mit, was eine nicht aktivierte und aktivierte Ausnahme ist.
Überprüfte Ausnahmen müssen explizit abgefangen oder weitergegeben werden, wie unter Grundlegende Behandlung von try-catch-finally-Ausnahmen beschrieben. Nicht aktivierte Ausnahmen haben diese Anforderung nicht. Sie müssen nicht gefangen oder für geworfen erklärt werden.
Überprüfte Ausnahmen in Java erweitern die Klasse java.lang.Exception. Nicht aktivierte Ausnahmen erweitern die java.lang.RuntimeException.
Die öffentliche Klasse NullPointerException erweitert die RuntimeException
Nicht aktivierte Ausnahmen erweitern die java.lang.RuntimeException. Deshalb ist NullPointerException eine Uncheked-Ausnahme.
Nehmen wir ein Beispiel: Beispiel 1:
Das Programm wird erfolgreich kompiliert. Beispiel 2:
Das Programm wird auch erfolgreich kompiliert. Daher ist es offensichtlich, dass bei ungeprüften Ausnahmen nichts passiert. Schauen wir uns nun an, was bei geprüften Ausnahmen passiert. Beispiel 3: Wenn sowohl die Basisklasse als auch die untergeordnete Klasse eine aktivierte Ausnahme auslösen
Das Programm wird erfolgreich kompiliert. Beispiel 4: Wenn die untergeordnete Klassenmethode eine randgeprüfte Ausnahme auslöst, verglichen mit derselben Methode der Basisklasse.
Das Programm kann nicht kompiliert werden. Wir müssen also vorsichtig sein, wenn wir geprüfte Ausnahmen verwenden.
quelle
Angenommen, Sie haben eine Superklasse A mit der Methode M1, die E1 wirft, und die Klasse B, die von A abgeleitet ist, wobei die Methode M2 M1 überschreibt. M2 kann nichts UNTERSCHIEDLICHES oder WENIGER SPEZIALISIERTES als E1 werfen.
Aufgrund des Polymorphismus sollte der Klient, der Klasse A verwendet, in der Lage sein, B so zu behandeln, als wäre es A. Inharitance ===> Is-a (B ist-a A). Was ist, wenn dieser Code, der sich mit Klasse A befasst, die Ausnahme E1 behandelt, da M1 deklariert, dass er diese überprüfte Ausnahme auslöst, dann aber ein anderer Ausnahmetyp ausgelöst wurde? Wenn M1 eine IOException auslösen würde, könnte M2 eine FileNotFoundException auslösen, da es sich um eine IOException handelt. Kunden von A konnten dies problemlos handhaben. Wenn die ausgelöste Ausnahme weiter gefasst wäre, hätten Kunden von A keine Chance, davon zu erfahren, und hätten daher keine Chance, sie zu fangen.
quelle
Nun, java.lang.Exception erweitert java.lang.Throwable. java.io.FileNotFoundException erweitert java.lang.Exception. Wenn also eine Methode java.io.FileNotFoundException auslöst, können Sie in der Override-Methode nichts höher in der Hierarchie als FileNotFoundException auslösen, z. B. können Sie java.lang.Exception nicht auslösen. Sie können jedoch eine Unterklasse von FileNotFoundException auslösen. Sie wären jedoch gezwungen, die FileNotFoundException in der Überschreibungsmethode zu behandeln. Knock up ein Code und probieren Sie es aus!
Die Regeln sind vorhanden, damit Sie die ursprüngliche Wurfdeklaration nicht verlieren, indem Sie die Spezifität erweitern, da der Polymorphismus bedeutet, dass Sie die Überschreibungsmethode für die Oberklasse aufrufen können.
quelle
Die überschreibende Methode darf KEINE geprüften Ausnahmen auslösen, die neu oder umfassender sind als die von der überschriebenen Methode deklarierten.
Beispiel:
quelle
Die überschreibende Methode darf KEINE geprüften Ausnahmen auslösen, die neu oder umfassender sind als die von der überschriebenen Methode deklarierten.
Dies bedeutet einfach, dass beim Überschreiben einer vorhandenen Methode die Ausnahme, die diese überladene Methode auslöst, entweder dieselbe Ausnahme sein sollte, die die ursprüngliche Methode auslöst, oder eine ihrer Unterklassen .
Beachten Sie, dass die Überprüfung, ob alle überprüften Ausnahmen behandelt werden, zur Kompilierungszeit und nicht zur Laufzeit erfolgt. Zur Kompilierungszeit selbst überprüft der Java-Compiler den Ausnahmetyp, den die überschriebene Methode auslöst. Da nur zur Laufzeit entschieden werden kann, welche überschriebene Methode ausgeführt wird, können wir nicht wissen, welche Art von Ausnahme wir abfangen müssen.
Beispiel
Nehmen wir an, wir haben eine Klasse
A
und ihre UnterklasseB
.A
hat Methodem1
und KlasseB
hat diese Methode überschrieben (nennen wir siem2
, um Verwirrung zu vermeiden ..). Sagen wir jetztm1
WürfeE1
undm2
WürfeE2
, das istE1
die Oberklasse. Jetzt schreiben wir den folgenden Code:Beachten Sie, dass dies
m1
nichts anderes als ein Aufruf von istm2
(auch hier sind Methodensignaturen bei überladenen Methoden gleich, also verwechseln Sie sich nicht mitm1
undm2
... sie dienen nur zur Unterscheidung in diesem Beispiel ... beide haben dieselbe Signatur). Zum Zeitpunkt der Kompilierung geht der Java-Compiler jedoch nur zum Referenztyp (A
in diesem Fall Klasse ). Er überprüft die Methode, ob sie vorhanden ist, und erwartet, dass der Programmierer sie verarbeitet. Sie werden also offensichtlich werfen oder fangenE1
. Nun, zur Laufzeit, wenn die überladene Methode löstE2
, wasE1
die Oberklasse ist, dann ... nun, es ist sehr falsch (aus dem gleichen Grund, den wir nicht sagen könnenB myBObj = new A()
). Daher erlaubt Java dies nicht. Nicht aktivierte Ausnahmen, die von der überladenen Methode ausgelöst werden, müssen identisch, unterklassig oder nicht vorhanden sein.quelle
Um dies zu verstehen, betrachten wir ein Beispiel, in dem wir eine Klasse haben, die eine Methode
Mammal
definiertreadAndGet
, die eine Datei liest, eine Operation daran ausführt und eine Instanz der Klasse zurückgibtMammal
.Class
Human
erweitert classMammal
und überschreibt diereadAndGet
Methode, um die Instanz vonHuman
anstelle der Instanz von zurückzugebenMammal
.Um anzurufen, müssen
readAndGet
wir behandeln,IOException
weil es eine überprüfte Ausnahme ist und SäugetierereadAndMethod
es werfen.Und wir wissen, dass der Compiler
mammal.readAndGet()
vom Objekt der Klasse aufgerufen wird,Mammal
aber zur Laufzeit löst JVM denmammal.readAndGet()
Methodenaufruf in einen Aufruf der Klasse auf,Human
weil ermammal
hältnew Human()
.Verfahren
readAndMethod
vonMammal
wirft ,IOException
und weil es eine geprüfte Ausnahme Compiler ist uns , es zu fangen zwingen , wenn wir rufenreadAndGet
aufmammal
Angenommen,
readAndGet
inHuman
löst eine andere aktivierte Ausnahme aus, z. B. Exception, und wir wissenreadAndGet
, dass sie von der Instanz aufgerufen wird,Human
weil weilmammal
hältnew Human()
.Da für den Compiler die Methode aufgerufen
Mammal
wird, zwingt uns der Compiler, nur zu behandeln,IOException
aber zur Laufzeit wissen wir, dass die Methode eineException
Ausnahme auslöst, die nicht behandelt wird, und unser Code wird unterbrochen, wenn die Methode die Ausnahme auslöst.Aus diesem Grund wird dies auf Compilerebene selbst verhindert, und wir dürfen keine neuen oder umfassenderen geprüften Ausnahmen auslösen, da dies am Ende nicht von JVM behandelt wird.
Es gibt auch andere Regeln, die wir beim Überschreiben der Methoden befolgen müssen, und Sie können mehr darüber lesen, warum wir Regeln zum Überschreiben von Methoden befolgen sollten , um die Gründe zu kennen.
quelle
Welche Erklärung schreiben wir dem Folgenden zu?
Die Klasse DerivedClass.java löst eine Ausnahme zur Kompilierungszeit aus, wenn die Druckmethode eine Ausnahme auslöst. Die print () -Methode der Basisklasse löst keine Ausnahme aus
Ich kann dies auf die Tatsache zurückführen, dass Exception schmaler als RuntimeException ist. Es kann sich entweder um No Exception (Runtime-Fehler), RuntimeException und deren untergeordnete Ausnahmen handeln
quelle
Die überschreibende Methode der Unterklasse kann nur mehrere geprüfte Ausnahmen auslösen, die Unterklassen der geprüften Ausnahme der Oberklassenmethode sind, kann jedoch nicht mehrere geprüfte Ausnahmen auslösen, die nicht mit der geprüften Ausnahme der Oberklassenmethode zusammenhängen
quelle
Java gibt Ihnen die Möglichkeit , Ausnahmen in der übergeordneten Klasse einzuschränken, da davon ausgegangen wird, dass der Client das Abfangen einschränkt . Meiner Meinung nach sollten Sie diese "Funktion" im Wesentlichen niemals verwenden, da Ihre Kunden möglicherweise später Flexibilität benötigen.
Java ist eine alte Sprache, die schlecht gestaltet ist. Moderne Sprachen haben keine solchen Einschränkungen. Der einfachste Weg, um diesen Fehler zu umgehen, besteht darin, Ihre Basisklasse
throw Exception
immer zu erstellen . Clients können spezifischere Ausnahmen auslösen, aber Ihre Basisklassen sind wirklich breit.quelle
Regel für die Behandlung von Überprüfungen und nicht aktivierten Ausnahmen für überschriebene Methoden
- Wenn die übergeordnete Klassenmethode keine Ausnahme deklariert , kann die übergeordnete Methode der untergeordneten Klasse deklarieren :
-Wenn die übergeordnete Klassenmethode eine ungeprüfte Ausnahme deklariert , kann die überschreibende Methode der untergeordneten Klasse deklarieren :
- Wenn die Methode der übergeordneten Klasse die aktivierte Ausnahme deklariert , kann die Methode zum Überschreiben der untergeordneten Klasse deklarieren :
Alle obigen Schlussfolgerungen gelten auch dann, wenn die Kombination aus aktivierter und nicht aktivierter Ausnahme in der Methode der übergeordneten Klasse deklariert ist
Ref
quelle