new
und 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).
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 Truck
Klasse 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:
-
Als Erstes werden die statischen Variablen der
Vehicle
Klasse initialisiert . Ja, ich sagte dieVehicle
Klasse, nichtTruck
. Statische Variablen werden vor dem Aufruf von Konstruktoren initialisiert, und dies beginnt in der übergeordneten Klasse. Versuchen wir, dies zu überprüfen. Wir setzen dasvehicleCounter
Feld in der Klasse auf 10 und versuchen, es sowohl im Konstruktor als auchVehicle
anzuzeigen .Vehicle
Truck
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
Truck
Konstruktors platziert, um sicherzustellen, dass die Felder des LKWs noch nicht initialisiert wurden, wennvehicleCounter
sie angezeigt wird.Und hier ist das Ergebnis:
10 10
-
Nachdem die statischen Variablen der übergeordneten Klasse initialisiert wurden, werden die statischen Variablen der untergeordneten Klasse initialisiert. In unserem Fall ist dies das
truckCounter
Feld derTruck
Klasse.Führen wir ein weiteres Experiment durch, bei dem wir versuchen, den Wert von
truckCounter
imTruck
Konstruktor 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
. -
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 :)
description
Als Experiment können wir der Variablen in der Klasse einen Anfangswert zuweisenVehicle
und 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
Vehicle
dem Feld zu Beginn des Konstruktorsdescription
bereits ein Wert zugewiesen wurde. -
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
Vehicle
Basisklassenkonstruktor und die zweite imTruck
Konstruktor. Wir müssen davon überzeugt sein, dass die Zeile darinVehicle
zuerst 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.
-
Jetzt ist es Zeit für die Initialisierung der nicht statischen Felder der untergeordneten Klasse, also unserer
Truck
Klasse. 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üfenmaxSpeed
im 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
-
Der Konstruktor der
Truck
untergeordneten 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 :)