CodeGym /Java-Blog /Random-DE /Abfolge von Aktionen während der Objekterstellung
Autor
Pavlo Plynko
Java Developer at CodeGym

Abfolge von Aktionen während der Objekterstellung

Veröffentlicht in der Gruppe Random-DE
Hallo! Die heutige Lektion wird ziemlich... äh... vielfältig sein :) in dem Sinne, dass wir ein breites Spektrum an Themen abdecken, die sich jedoch alle auf den Prozess der Objekterstellung beziehen . Reihenfolge der Aktionen bei der Objekterstellung - 1Wir werden es von Anfang bis Ende analysieren: wie Konstruktoren aufgerufen werden, wie und in welcher Reihenfolge Felder (einschließlich statischer Felder) initialisiert werden usw. Wir haben bereits einige der im Artikel besprochenen Punkte angesprochen, sodass Sie einen Blick darauf werfen können Das Material zu Basisklassenkonstruktoren . Erinnern wir uns zunächst daran, wie ein Objekt erstellt wird. Sie erinnern sich noch gut daran, wie dieser Prozess aus der Sicht eines Entwicklers aussieht: Er erstellt eine Klasse, schreibt newund alles ist fertig :) Hier sprechen wir darüber, was im Computer und in der Java-Maschine passiert, wenn wir schreiben, zum Beispiel:

Cat cat = new Cat();
Darüber haben wir bereits gesprochen, aber für alle Fälle möchten wir Sie daran erinnern:
  • Zunächst wird Speicher zum Speichern des Objekts zugewiesen.
  • Als nächstes erstellt die Java-Maschine eine Referenz auf das Objekt (in unserem Fall lautet die Referenz Cat cat).
  • Abschließend werden Variablen initialisiert und der Konstruktor aufgerufen (wir werden uns diesen Vorgang genauer ansehen).
Darüber hinaus erinnern Sie sich wahrscheinlich aus der Lektion zum Objektlebenszyklus daran, dass ein Objekt so lange existiert, wie es mindestens eine Referenz darauf gibt. Wenn keine mehr vorhanden sind, wird das Objekt zur Beute des Garbage Collectors. Reihenfolge der Aktionen bei der Objekterstellung - 2Diese ersten beiden Punkte sollten keine besonderen Fragen aufwerfen. Die Speicherzuweisung ist ein einfacher Vorgang und es gibt nur zwei mögliche Ergebnisse: Entweder ist Speicher vorhanden oder nicht :) Und das Erstellen eines Links ist nicht ungewöhnlich. Aber der dritte Punkt stellt eine ganze Reihe von Operationen dar, die in strenger Reihenfolge ausgeführt werden. Ich bin kein Fan von Pauken für Tests, aber Sie müssen diesen Prozess gut verstehen und sich diese Abfolge von Vorgängen merken. Als wir in den vorherigen Lektionen über den Objekterstellungsprozess gesprochen haben, wussten Sie noch nicht wirklich etwas über Vererbung, daher war es problematisch, einige Dinge zu erklären. Jetzt wissen Sie ziemlich viel und wir können uns dieser Frage endlich ausführlich widmen :) Der dritte Punkt lautet also: „ Zuletzt werden Variablen initialisiert und der Konstruktor aufgerufen. “ Aber in welcher Reihenfolge geschieht das alles? Zum besseren Verständnis erstellen wir zwei supereinfache Klassen – eine übergeordnete und eine untergeordnete Klasse:

public class Vehicle { 

   public static int vehicleCounter = 0; 

   private String description = "Vehicle"; 
   public Vehicle() { 
   } 

   public String getDescription() { 
       return description; 
   } 
} 

public class Truck extends Vehicle { 

   private static int truckCounter = 0; 

   private int yearOfManufacture; 
   private String model; 
   private int maxSpeed; 

   public Truck(int yearOfManufacture, String model, int maxSpeed) { 
       this.yearOfManufacture = yearOfManufacture; 
       this.model = model; 
       this.maxSpeed = maxSpeed; 

       Vehicle.vehicleCounter++; 
       truckCounter++; 
   } 
}
Die TruckKlasse ist eine Implementierung eines Lkw mit Feldern, die sein Jahr, sein Modell und seine Höchstgeschwindigkeit darstellen. Nun wollen wir ein solches Objekt erstellen:

public class Main { 

   public static void main(String[] args) throws IOException { 

       Truck truck = new Truck(2017, "Scania S 500 4x2", 220); 
   } 
}
Für die Java-Maschine sieht der Prozess folgendermaßen aus:
  1. Als Erstes werden die statischen Variablen der VehicleKlasse initialisiert . Ja, ich sagte die VehicleKlasse, nicht Truck. Statische Variablen werden vor dem Aufruf von Konstruktoren initialisiert, und dies beginnt in der übergeordneten Klasse. Versuchen wir, dies zu überprüfen. Wir setzen das vehicleCounterFeld in der Klasse auf 10 und versuchen, es sowohl im Konstruktor als auch Vehicleanzuzeigen .VehicleTruck

    
    public class Vehicle { 
    
       public static int vehicleCounter = 10; 
       private String description = "Vehicle"; 
    
       public Vehicle() { 
           System.out.println(vehicleCounter); 
       } 
    
       public String getDescription() { 
           return description; 
       } 
    } 
    
    public class Truck extends Vehicle { 
    
       private static int truckCount = 0;
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
           System.out.println(vehicleCounter); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCount++; 
       } 
    }
    

    Wir haben die println-Anweisung bewusst ganz am Anfang des TruckKonstruktors platziert, um sicherzustellen, dass die Felder des LKWs noch nicht initialisiert wurden, wenn vehicleCountersie angezeigt wird.

    Und hier ist das Ergebnis:

    
    10 
    10
    
  2. Nachdem die statischen Variablen der übergeordneten Klasse initialisiert wurden, werden die statischen Variablen der untergeordneten Klasse initialisiert. In unserem Fall ist dies das truckCounterFeld der TruckKlasse.

    Führen wir ein weiteres Experiment durch, bei dem wir versuchen, den Wert von truckCounterim TruckKonstruktor anzuzeigen, bevor die anderen Felder initialisiert werden:

    
    public class Truck extends Vehicle { 
    
       private static int truckCounter = 10; 
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
           System.out.println(truckCounter); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCounter++; 
       } 
    }
    

    Wie Sie sehen können, wurde unserer statischen Variablen zu Beginn des Konstruktors bereits der Wert 10 zugewiesen Truck.

  3. Es ist noch nicht die Zeit für die Konstrukteure! Die Variableninitialisierung wird fortgesetzt. Die nicht statischen Variablen der übergeordneten Klasse werden als drittes initialisiert. Wie Sie sehen, verkompliziert die Vererbung den Prozess der Objekterstellung erheblich, aber Sie können nichts dagegen tun: Sie müssen sich nur einige Dinge beim Programmieren merken :)

    descriptionAls Experiment können wir der Variablen in der Klasse einen Anfangswert zuweisen Vehicleund ihn dann im Konstruktor ändern.

    
    public class Vehicle { 
    
       public static int vehicleCounter = 10; 
    
       private String description = "Initial value of the description field"; 
    
       public Vehicle() { 
           System.out.println(description); 
           description = "Vehicle"; 
           System.out.println(description); 
       } 
    
       public String getDescription() { 
           return description; 
       } 
    }
    

    Lassen Sie uns unsere main()Methode ausführen, die einen LKW erstellt:

    
    public class Main { 
    
       public static void main(String[] args) throws IOException { 
    
           Truck truck = new Truck(2017, "Scania S 500 4x2", 220); 
       } 
    }
    

    Wir erhalten folgendes Ergebnis:

    
    Initial value of the description field 
    Vehicle
    

    Dies beweist, dass Vehicledem Feld zu Beginn des Konstruktors descriptionbereits ein Wert zugewiesen wurde.

  4. Endlich ist es Zeit für die Konstrukteure! Genauer gesagt ist es Zeit für den Basisklassenkonstruktor. Es wird im vierten Schritt des Objekterstellungsprozesses aufgerufen.

    Dies lässt sich auch relativ einfach überprüfen. Versuchen wir, zwei Zeilen an die Konsole auszugeben: eine im VehicleBasisklassenkonstruktor und die zweite im TruckKonstruktor. Wir müssen davon überzeugt sein, dass die Zeile darin Vehiclezuerst angezeigt wird:

    
    public Vehicle() { 
    
       System.out.println("Hello from the Vehicle constructor!"); 
    } 
    
    public Truck(int yearOfManufacture, String model, int maxSpeed) { 
    
       System.out.println("Hello from the Truck constructor!"); 
       this.yearOfManufacture = yearOfManufacture; 
       this.model = model; 
       this.maxSpeed = maxSpeed; 
    
       Vehicle.vehicleCounter++; 
       truckCounter++; 
    }
    

    Wir führen unsere main()Methode aus und schauen uns das Ergebnis an:

    
    Hello from the Vehicle constructor! 
    Hello from the Truck constructor! 
    

    Exzellent. Das heißt, wir irren uns nicht :) Machen wir weiter.

  5. Jetzt ist es Zeit für die Initialisierung der nicht statischen Felder der untergeordneten Klasse, also unserer TruckKlasse. Die Felder unmittelbar innerhalb der zu instanziierenden Klasse werden erst im fünften Schritt initialisiert! Überraschend, aber wahr :) Auch hier führen wir eine einfache Prüfung durch – genau wie bei der übergeordneten Klasse: Wir geben der Variablen einen Anfangswert und prüfen maxSpeedim Konstruktor, ob der Wert zugewiesen wurde, bevor der Konstruktor gestartet wurde:Truck

    
    public class Truck extends Vehicle { 
    
       private static int truckCounter = 10; 
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed = 150; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
    
           System.out.println("Initial value of maxSpeed = " + this.maxSpeed); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCounter++; 
       } 
    }
    

    Konsolenausgabe:

    
    Initial value of maxSpeed = 150
    

    Wie Sie sehen können,   beträgt der Wert beim Start des Truck Konstruktors bereits 150!maxSpeed

  6. Der Konstruktor der Truckuntergeordneten Klasse wird aufgerufen.

    Und erst an dieser Stelle wird als letztes der Konstruktor der Klasse aufgerufen, die wir instanziieren!

    Erst im sechsten Schritt werden den Feldern die Werte zugewiesen, die wir als Argumente an unseren LKW übergeben.

    Wie Sie sehen, ist das „Konstruieren“ eines Lkw, also der Objekterstellungsprozess, nicht einfach. Aber es scheint, dass wir es in die kleinsten Teile zerlegt haben :)

Reihenfolge der Aktionen bei der Objekterstellung - 3 Warum ist es so wichtig, diesen Prozess gut zu verstehen? Stellen Sie sich vor, wie unerwartet die Ergebnisse beim Erstellen eines gewöhnlichen Objekts sein könnten, wenn Sie nicht genau wüssten, was „unter der Haube“ passiert :) Jetzt ist es an der Zeit, zum Kurs zurückzukehren und einige Aufgaben zu erledigen! Viel Glück und bis bald! :) :)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION