2015-08-27 12 views
13

Ich baute etwas, das ich nicht wirklich verstehe - ich weiß nicht, wie es funktioniert. Ich habe mich mit dieser multicatch explaination article vertraut gemacht.Ermitteln der Kompilierungszeit Multicatch-Ausnahmetyp

Betrachten Sie diese zwei Ausnahmen und Code:

public class MyException1 extends Exception { 
    // constructors, etc 
    String getCustomValue(); 
} 

public class MyException2 extends Exception { 
    // constructors, etc 
    String getCustomValue() { return "foo"; } 
} 

try { 
    //... 
} catch (MyException1|MyException2 e) { 
    e.getCustomValue(); // won't work, as I expected 
} 

ich nicht in der Lage sein getCustomValue() zu nennen, auch wenn das Verfahren ist das gleiche, weil innerhalb Java die oben try/catch soll, um tatsächlich die MyException1/2 werden Gießen zu Exception (so habe ich die Dokumente verstanden).

Wenn ich jedoch eine Schnittstelle wie folgt vorstellen:

public interface CustomValueGetter { 
    String getCustomValue(); 
} 

public class MyException1 extends Exception implements CustomValueGetter /*...*/ 
public class MyException2 extends Exception implements CustomValueGetter /*...*/ 

und fügen Sie ihn auf beide Ausnahmen, Java ist tatsächlich in der Lage, mir zu erlauben, dass die Methode zu verwenden. Und dann ruft dies gilt:

try { 
    //... 
} catch (MyException1|MyException2 e) { 
    e.getCustomValue(); // does work 
} 

Kurz gesagt, meine Frage ist: was tatsächlich geschieht hier: (MyException1|MyException2 e).

Was ist e?

  • ist die nächste übergeordnete Klasse als Typ der e gewählt? This question asks about it und das ist angeblich die Antwort. Wenn ja, warum ist dann die Schnittstelle CustomValueGetter "sichtbar" wenn ich auf e zugreife? Es sollte nicht sein, wenn in meinem Fall e ein Exception ist.

  • Und wenn nicht, wenn die echte Klasse entweder MyException1 oder MyException2 ist, warum kann ich nicht einfach die gleiche Methode für diese beiden Klassen aufrufen?

  • Ist e eine Instanz einer dynamisch generierten Klasse, die alle gemeinsamen Schnittstellen der beiden Ausnahmen implementiert und vom nächstliegenden Typ ist?

Antwort

4

Wie Ischuetze sagte, sucht e nach der Klasse oder Schnittstelle, die beide Ausnahmen gemeinsam haben. In Ihrem ersten Beispiel kann keine Sharing-Klasse trotz der Exception-Klasse gefunden werden, daher kann sie nur die von ihr bereitgestellten Methoden verwenden.

Wenn Sie Ihr Beispiel in diesen Code ändern, können Sie es erneut kompilieren.

public class MyException12 extends Exception { 
    public String getCustomValue(){ return "boo"; }; 
} 

public class MyException1 extends MyException12{ 
    public String getCustomValue() { return "foo"; }; 
} 

public class MyException2 extends MyException12{ 
    // constructors, etc 
    public String getCustomValue() { return "foo"; }; 
} 

Wie in Ihrem Beispiel mit der Schnittstelle teilt die Ausnahme, dass beide MyException1 und MyException2 haben MyException12 und somit in der Lage, Es sind Funktionen zu nutzen.

Here ist eine SO Frage, die das ganze Problem beantwortet und was die Art von e sein wird.

ein Zitat aus dem Link in der Antwort:

die Handhabung von Ausnahmetypen ändern, wirkt sich die Art System auf zweierlei Weise: Neben der üblichen Art auf allen durchgeführten Prüfung unterziehen Ausnahmetypen eine zusätzliche Kompilierzeit Analyse. Für die Typüberprüfung hat ein mit einer Disjunktion deklarierter catch-Parameter den Typ lub (t1, t2, ...) (JLSv3 §15.12.2.7), wobei die ti die Ausnahmetypen sind, für die die catch-Klausel deklariert ist. Informell ist die Iub (kleinste Obergrenze) der spezifischste Supertyp der fraglichen Typen. Im Falle eines Multi-Catch-Exception-Parameters existiert immer die kleinste Obergrenze der fraglichen Typen, da die Typen aller abgefangenen Exceptions Unterklassen von Throwable sein müssen. Daher ist Throwable eine Obergrenze der fraglichen Typen, aber es ist möglicherweise nicht die kleinste Obergrenze, da eine Unterklasse von Throwable eine Oberklasse (und damit auch ein Supertyp) der fraglichen Typen und der betreffenden Ausnahmetypen sein kann Implementieren einer gemeinsamen Schnittstelle. (Ein lub kann ein Schnitttyp einer Oberklasse und einer oder mehrerer Schnittstellen sein.) Zum Zweck der Ausnahmebestimmung (JLSv3 §11.2) ist eine throw-Anweisung (JLSv3 §11.2.2), die einen finalen oder effektiv endgültigen catch-Parameter zurückführt behandelt, als würde genau diese Ausnahmearten werfen, die:

+0

Wenn die angenommene Antwort des Links in Ihrer Antwort richtig ist, dann sollte die Schnittstelle, die ich verwendete, niemals in 'e' aufgelöst werden, weil die Oberklasse dieser beiden Ausnahmen es nicht implementiert. – Dariusz

+1

@Dariusz ich edid und zitiert den Link in der Antwort auf die andere Frage, Benachrichtigen Sie den späteren Teil sagen: 'Ein Iub kann eine Kreuzung Typ einer Oberklasse und eine oder mehrere Schnittstellen sein. – SomeJavaGuy

+1

Schade, dass die Formulierung nicht gemacht es in die eigentliche Java-Sprache Dokumentation (die sehr dunkel geschrieben ist). Ich denke, das ist die Beschreibung von [Intersection Types] (https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.9), die "Typ-Inferenz (§15.12.2.7) ", und ebenso die Beschreibung der [Fangklausel] (https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20-510). – Andreas

4

Im ersten Codebeispiel Java nicht automatisch Folgerung, dass beide MyException1 und MyException2getCustomValue die Funktion implementieren. So ist e der größte gemeinsame Nenner in der Typhierarchie beider; das ist Exception und hat nicht die Funktion getCustomValue. Also, es funktioniert nicht.

Java ist stark typisiert und trotzdem werden die Funktionen ähnlich benannt, es ist nicht dasselbe, als ob sie im selben Typ deklariert sind.

Im zweiten Code implementieren beide Ausnahmen CustomValueGetter. Somit ist e der größte gemeinsame Nenner CustomValueGetter, der getCustomValue implementiert.

2

Digging on @Kevin Eshche JLS Link Ich habe offenbar eine richtige Antwort gefunden.

Zur Kompilierungszeit e ist eigentlich eine mindestens obere Grenze, die in JLS-15.12.2.7 definiert ist.

Ein Auszug aus der Dokumentation:

die Kreuzung Computing ist komplizierter, als man zuerst realisieren. Vorausgesetzt, ein Typparameter ist auf einen Supertyp von zwei verschiedenen Aufrufen eines generischen Typs beschränkt, z. B. Liste und Liste, könnte die naive Überschneidungsoperation Object ergeben. Eine ausgefeiltere Analyse ergibt jedoch eine Menge, die List enthält. Wenn ein Typparameter T auf einen Supertyp von zwei nicht verwandten Interfaces I und J beschränkt ist, können wir möglicherweise T als Object ableiten, oder wir erhalten eine engere Grenze von I & J. Diese Ausgaben werden in weiteren diskutiert Details später in diesem Abschnitt.

Kurz gesagt, es ist ein class des nächsten gemeinsamen Supertyp aller | ‚d Ausnahmen (in meinem Fall ein Exception) und implementiert alle Schnittstellen alle Ausnahmen zu tun (in meinem Fall, CustomValueGetter und Serializable) .