Weil es normalerweise in einer bestimmten Android-Bibliothek verwendet wurde.
Sehen Sie plötzlich die Ausgabe der folgenden Implementierung?
public class Main {
static class Foo {
public Foo() {
init();
}
protected void init() {
}
}
static class Bar extends Foo {
private int val1;
private int val2 = 0;
@Override
protected void init() {
val1 = 1;
val2 = 2;
}
}
public static void main(String... args) {
Bar bar = new Bar();
System.out.println(bar.val1);
System.out.println(bar.val2);
}
}
Das Ausgabeergebnis ist wie folgt.
1
0
Die Foo
Klasse ist ein Konstruktor, der die init ()
Methode aufruft.
Die "Bar" -Klasse ist eine Unterklasse von "Foo", die die von "Foo" erstellte "init ()" - Methode zum Initialisieren von Mitgliedsvariablen überschreibt.
In "Bar.init ()" werden den Mitgliedsvariablen "val1" und "val2" "1" bzw. "2" zugewiesen.
Wenn Sie diese "Bar" -Klasse instanziieren und jeden Wert ausgeben, enthält "val1" "1", wie Sie sehen können, aber der Wert von "val2", dem "2" hätte zugewiesen werden sollen, ist "0" Es ist `.
Es gibt zwei Schlüssel, um dieses Phänomen zu enträtseln.
Eine ist die Definition von Mitgliedsvariablen und die andere ist der Initialisierungszeitpunkt von Variablen in Java.
In dem fraglichen Code sind die Mitgliedsvariablen der Klasse "Bar" wie folgt definiert:
Bar
private int val1;
private int val2 = 0;
In Bezug auf die Definition von Elementvariablen wird "0" für Grundelemente und "Null" für Klassen zugewiesen, wenn keine explizite Initialisierung durchgeführt wird. Selbst wenn es mit "0" initialisiert wird, ändert sich sein Verhalten abhängig davon, ob es explizit initialisiert wird oder nicht.
In Java erfolgt die Initialisierung der Mitgliedsvariablen im Konstruktor. Die Frage ist, wann es im Konstruktor passiert.
Da ich denke, dass ich es normalerweise beiläufig schreibe, erfolgt die Initialisierung der Mitgliedsvariablen tatsächlich ** unmittelbar nach dem Aufruf des Konstruktors der übergeordneten Klasse **.
Mit anderen Worten
Foo
static class Foo {
public Foo() {
← hier
init();
}
}
ist.
Ich glaube, Sie können nichts sehen, aber Javas Konstruktor erfordert ** den Aufruf des Konstruktors der übergeordneten Klasse am Anfang des Konstruktors **. Es gibt jedoch eine Bedingung, die weggelassen werden kann: ** Die übergeordnete Klasse definiert den Standardkonstruktor **. Der Standardkonstruktor ist ein Konstruktor, der keine Argumente akzeptiert. (Genau genommen ist es möglicherweise nicht der übergeordnete Konstruktor, aber ich werde es weglassen.)
Im obigen Code ist es also dasselbe wie ein super ()
Aufruf an der Pfeilposition.
Auf der Grundlage des oben Gesagten werde ich die Falle erklären, auf die ich in dem fraglichen Code getreten bin.
Es war die Bar-Klasse, die in die Falle trat.
Bar
static class Bar extends Foo {
private int val1;
private int val2 = 0;
@Override
protected void init() {
val1 = 1;
val2 = 2;
}
}
Wenn Sie diese Klasse schreiben, ohne sie wegzulassen, sieht sie wie folgt aus.
Bar
static class Bar extends Foo {
private int val1;
private int val2 = 0;
public Bar() {
super();
}
@Override
protected void init() {
val1 = 1;
val2 = 2;
}
}
Der Konstruktor "Bar" ruft "super ()" auf, dh den Konstruktor "Foo". Der Konstruktor "Foo" ruft "init ()" auf, was eine Überschreibung der "Bar" -Klasse darstellt, also einen Aufruf von "Bar.init ()".
Wenn Sie diesen Fluss grob erweitern
Bar() {
super() {
Bar.init() {
Bar.val1 = 1;
Bar.val2 = 2;
}
}
Initialisierung von Balkenelementvariablen() {
Bar.val2 = 0;
}
}
Es wird der Fluss sein.
Wird val1
nach super ()
nicht mit 0
initialisiert? Sie können denken, dass der Initialisierungsprozess selbst nach "super ()" nicht ausgeführt wird, wenn er zum Zeitpunkt der Definition nicht initialisiert wird.
Übrigens, wenn Sie vor dem Zuweisen eines Werts auf "val2" von "Bar.init ()" verweisen, wird "0" zurückgegeben. Stellen Sie sich vor, dass allen Elementvariablen unabhängig von der Initialisierung der Elementdefinition "0" oder "Null" zugewiesen wird und der nach "super ()" angegebene Wert zugewiesen wird.
Die erste Implementierung, die ich veröffentlicht habe, ist der Mistcode. Warum also nicht verwenden, nachdem ich die Vererbung verstanden habe?
(Es hätte offiziell geschrieben werden sollen, aber ich habe den Link vergessen. Wenn ich ihn finde, werde ich ihn einfügen ...)
Recommended Posts