Ich glaube, dass viele Schüler auf diese Art von Frage gestoßen sind. Sie haben die Informationen möglicherweise nachgeschlagen und sie dann vergessen. Wenn sie darauf stoßen, können sie sie immer noch nicht richtig beantworten. Als Nächstes werde ich Sie in vier Schritten dazu bringen, die Ausführungssequenz dieses Codes zu zerlegen und die Regeln zusammenzufassen.
Eine Eröffnungsfrage zur Untersuchung der Codeausführungssequenz:
public class Parent { static { System.out.println("Parent static initial block"); } { System.out.println("Parent initial block"); } public Parent() { System.out.println("Parent constructor block"); } } public class Child extends Parent { static { System.out.println("Child static initial block"); } { System.out.println("Child initial block"); } private Hobby hobby = new Hobby(); public Child() { System.out.println("Child constructor block"); } } public class Hobby { static{ System.out.println("Hobby static initial block"); } public Hobby() { System.out.println("hobby constructor block"); } }
Was gibt der obige Code aus, wenn new Child() ausgeführt wird?
Ich glaube, dass viele Schüler auf ein solches Problem gestoßen sind. Möglicherweise haben sie die Informationen überprüft und sie dann vergessen. Wenn sie erneut darauf stoßen, können sie sie immer noch nicht richtig beantworten. Als Nächstes führt Sie der Klassensprecher durch vier Schritte, um die Ausführungssequenz dieses Codes zu zerlegen und die Regeln zusammenzufassen.
Die folgenden beiden Codeteile vergleichen die Änderungen vor und nach der Kompilierung:
Child.java vor der Kompilierung
public class Child extends Parent { static { System.out.println("Child static initial block"); } { System.out.println("Child initial block"); } private Hobby hobby = new Hobby(); public Child() { System.out.println("Child constructor block"); } }
Child.class nach der Kompilierung
public class Child extends Parent { private Hobby hobby; public Child() { System.out.println("Child initial block"); this.hobby = new Hobby(); System.out.println("Child constructor block"); } static { System.out.println("Child static initial block"); } }
Durch den Vergleich können Sie erkennen, dass der Compiler den Initialisierungsblöcken und Werte zuweist Instanzfelder werden vor den Konstruktorcode verschoben und die Reihenfolge der zugehörigen Codes bleibt erhalten. Wenn mehrere Konstruktoren vorhanden sind, wird der Initialisierungscode tatsächlich kopiert und verschoben.
Auf dieser Grundlage können wir die erste Prioritätsreihenfolge ermitteln:
Der Ladevorgang einer Klasse kann grob in drei Phasen unterteilt werden: Laden-> Link->
Gemäß Punkt 5 stellt die JVM sicher, dass die <clinit>-Methode der Unterklasse beibehalten wird.
Dies führt zur zweiten Prioritätsreihenfolge:
3. Statischer Code wird nur einmal ausgeführt
Wir Jeder weiß, dass statischer Code (außer statischen Methoden) nur einmal ausgeführt wird.
Haben Sie jemals darüber nachgedacht, wie dieser Mechanismus gewährleistet ist?
Das übergeordnete Delegationsmodell in JDK8 :
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 首先检查该类是否被加载过 // 如果加载过,直接返回该类 Class<?> c = findLoadedClass(name); if (c == null) { try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // 如果父类抛出ClassNotFoundException // 说明父类无法完成加载请求 } if (c == null) { // 如果父类无法加载,转由子类加载 c = findClass(name); } } if (resolve) { resolveClass(c); } return c; }
Aus dem von den Eltern delegierten Code geht hervor, dass eine Klasse unter demselben Klassenlader nur einmal geladen werden kann, was die Initialisierung auf nur einmal beschränkt. Daher wird der statische Code in der Klasse (mit Ausnahme statischer Methoden) nur einmal während der Klasseninitialisierung ausgeführt. <init>
Der vom Compiler automatisch generierte Klassenkonstruktor wurde zuvor eingeführt: < clinit>-Methode sammelt die Zuweisungsaktionen und statischen Anweisungsblöcke (static{}-Blöcke) aller statisch geänderten Klassenvariablen und behält die Reihenfolge des Erscheinens des Codes bei. Sie wird während der Klasseninitialisierung ausgeführt generiert auch eine < ;init>-Methode, sammelt die Zuweisungsaktion des Instanzfelds, den Code im Initialisierungsanweisungsblock ({}-Block) und den Konstruktor (Konstruktor) und behält die Reihenfolge des Erscheinens des Codes bei. Sie wird nach der neuen Anweisung ausgeführt
Wenn wir also eine neue Klasse erstellen und die JVM die Klasse nicht geladen hat, wird sie zuerst initialisiert und dann instanziiert.
An diesem Punkt kann die dritte Prioritätsregel herauskommen:
Gemäß der vorherigen Zusammenfassung werden der Initialisierungscode und der Konstruktorcode vom Compiler in <init> gesammelt, und der statische Code wird in <clinit> gesammelt, sodass die oben genannten Regeln erneut zusammengeführt werden: Übergeordnete Klasse
Üben wir es entsprechend der Frage am Anfang: <clinit>
> 子类<clinit>
> 父类 <init>
> 子类 <init>
Das obige ist der detaillierte Inhalt vonLassen Sie das statische Schlüsselwort in Java sofort verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!