Können Sie ein Codebeispiel nennen, bei dem etwas Schlimmes passieren würde, wenn der Compiler diese Einschränkung nicht hätte?
class Good {
int essential1;
int essential2;
Good(int n) {
if (n > 100)
throw new IllegalArgumentException("n is too large!");
essential1 = 1 / n;
essential2 = n + 2;
}
}
class Bad extends Good {
Bad(int n) {
try {
super(n);
} catch (Exception e) {
// Exception is ignored
}
}
public static void main(String[] args) {
Bad b = new Bad(0);
// b = new Bad(101);
System.out.println(b.essential1 + b.essential2);
}
}
Eine Ausnahme während der Konstruktion deutet fast immer darauf hin, dass das zu konstruierende Objekt nicht ordnungsgemäß initialisiert werden konnte, sich nun in einem schlechten Zustand befindet, unbrauchbar ist und entsorgt werden muss. Ein Konstruktor einer Unterklasse hat jedoch die Möglichkeit, eine in einer seiner Oberklassen aufgetretene Ausnahme zu ignorieren und ein teilweise initialisiertes Objekt zurückzugeben. Im obigen Beispiel, wenn das Argument, das an new Bad()
entweder 0 oder größer als 100 ist, dann ist weder essential1
noch essential2
ordnungsgemäß initialisiert sind.
Sie mögen sagen, dass es immer eine schlechte Idee ist, Ausnahmen zu ignorieren. OK, hier ist ein weiteres Beispiel:
class Bad extends Good {
Bad(int n) {
for (int i = 0; i < n; i++)
super(i);
}
}
Komisch, nicht wahr? Wie viele Objekte erstellen wir in diesem Beispiel? Eins? Zwei? Oder vielleicht gar nichts...
Erlaubt den Aufruf super()
o this()
in der Mitte eines Konstruktors würde die Büchse der Pandora für abscheuliche Konstruktoren öffnen.
Andererseits verstehe ich die häufige Notwendigkeit, einen statischen Teil vor einem Aufruf von super()
o this()
. Dies kann jeder Code sein, der sich nicht auf this
Referenz (die in der Tat bereits am Anfang eines Konstruktors existiert, aber nicht ordnungsgemäß verwendet werden kann, bis super()
o this()
zurück) und musste einen solchen Anruf tätigen. Außerdem besteht, wie bei jeder Methode, die Möglichkeit, dass einige lokale Variablen, die vor dem Aufruf von super()
o this()
wird danach benötigt.
In solchen Fällen haben Sie die folgenden Möglichkeiten:
- Verwenden Sie das Muster unter diese Antwort die es ermöglicht, die Beschränkung zu umgehen.
-
Warten Sie auf die Freigabe durch das Java-Team super()
und vor this()
Code. Dies kann dadurch geschehen, dass eine Beschränkung auferlegt wird, wo super()
o this()
kann in einem Konstruktor vorkommen. Tatsächlich ist sogar der heutige Compiler in der Lage, gute und schlechte (oder potenziell schlechte) Fälle so gut zu unterscheiden, dass eine statische Codeerweiterung am Anfang eines Konstruktors sicher möglich ist. Nehmen wir an, dass super()
y this()
return this
Referenz und Ihr Konstruktor hat seinerseits
return this;
am Ende. Außerdem lehnt der Compiler den Code ab
public int get() {
int x;
for (int i = 0; i < 10; i++)
x = i;
return x;
}
public int get(int y) {
int x;
if (y > 0)
x = y;
return x;
}
public int get(boolean b) {
int x;
try {
x = 1;
} catch (Exception e) {
}
return x;
}
mit der Fehlermeldung "Variable x wurde möglicherweise nicht initialisiert", könnte es dies bei this
Variable und überprüft sie wie jede andere lokale Variable. Der einzige Unterschied ist this
kann auf keine andere Weise zugewiesen werden als super()
o this()
Aufruf (und, wie üblich, wenn es keinen solchen Aufruf bei einem Konstruktor gibt, super()
wird vom Compiler implizit am Anfang eingefügt) und darf nicht doppelt zugewiesen werden. Im Zweifelsfall (wie bei der ersten get()
, donde x
tatsächlich immer zugewiesen wird), könnte der Compiler einen Fehler zurückgeben. Das wäre besser, als bei jedem Konstruktor einen Fehler zurückzugeben, bei dem etwas anderes als ein Kommentar vor super()
o this()
.
9 Stimmen
Eine gute Frage. Ich habe ein ähnliches Projekt gestartet valjok.blogspot.com/2012/09/ und programmers.exchange, wo ich zeige, dass es Fälle gibt, in denen Unterfelder vor dem super() initialisiert werden müssen. Die Funktion erhöht also die Komplexität, wobei nicht klar ist, ob die positiven Auswirkungen in Bezug auf die "Codesicherheit" die negativen überwiegen. Ja, es gibt negative Konsequenzen, wenn super immer zuerst kommt. Überraschenderweise hat dies niemand erwähnt. Ich denke, dass dies eine konzeptionelle Angelegenheit ist und in programmers.exchange gefragt werden muss.
60 Stimmen
Das Schlimmste daran ist, dass dies eine reine Java-Beschränkung ist. Auf der Bytecode-Ebene gibt es keine solche Einschränkung.
2 Stimmen
Nun, es wäre unmöglich, diese Einschränkung auf der Bytecode-Ebene zu haben - alle Beispiele in diesem Beitrag würden eine solche Einschränkung verletzen, auch die, die die gesamte Logik in einen einzigen Ausdruck packen.
0 Stimmen
Mögliches Duplikat von der Aufruf von super() muss die erste Anweisung im Konstruktorkörper sein