JavaRush /Java-Blog /Random-DE /Konstruktoren in Java

Konstruktoren in Java

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute befassen wir uns mit einem sehr wichtigen Thema, das unsere Objekte betrifft. Hier können wir ohne Übertreibung sagen, dass Sie dieses Wissen jeden Tag in der realen Arbeit anwenden werden! Wir werden über Konstrukteure sprechen. Möglicherweise hören Sie diesen Begriff zum ersten Mal, aber tatsächlich haben Sie wahrscheinlich Konstruktoren verwendet, es ist Ihnen aber selbst nicht aufgefallen :) Wir werden das später sehen.

Was ist ein Konstruktor in Java und warum wird er benötigt?

Schauen wir uns zwei Beispiele an.
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car bugatti = new Car();
       bugatti.model = "Bugatti Veyron";
       bugatti.maxSpeed = 407;

   }
}
Wir haben unser Auto erstellt und sein Modell und die Höchstgeschwindigkeit festgelegt. In einem realen Projekt verfügt das Car- Objekt jedoch eindeutig über mehr als zwei Felder. Und zum Beispiel 16 Felder!
public class Car {

   String model;//Modell
   int maxSpeed;//Höchstgeschwindigkeit
   int wheels;// Festplattenbreite
   double engineVolume;//Motorkapazität
   String color;//Farbe
   int yearOfIssue;//Baujahr
   String ownerFirstName;//Name des Besitzers
   String ownerLastName;//Nachname des Besitzers
   long price;//Preis
   boolean isNew;//neu oder nicht
   int placesInTheSalon;//Anzahl der Sitzplätze in der Kabine
   String salonMaterial;// Innenmaterial
   boolean insurance;//Ist es versichert?
   String manufacturerCountry;//Herstellungsland
   int trunkVolume;// Kofferraumvolumen
   int accelerationTo100km;//Beschleunigung auf 100 km/h in Sekunden


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

   }

}
Wir haben ein neues Car- Objekt erstellt . Ein Problem: Wir haben 16 Felder, aber wir haben nur 12 initialisiert ! Versuchen Sie es jetzt mit dem Code, um diejenigen zu finden, die wir vergessen haben! Gar nicht so einfach, oder? In einer solchen Situation kann der Programmierer leicht einen Fehler machen und die Initialisierung eines Feldes überspringen. Infolgedessen wird das Programmverhalten fehlerhaft:
public class Car {

   String model;//Modell
   int maxSpeed;//Höchstgeschwindigkeit
   int wheels;// Festplattenbreite
   double engineVolume;//Motorkapazität
   String color;//Farbe
   int yearOfIssue;//Baujahr
   String ownerFirstName;//Name des Besitzers
   String ownerLastName;//Nachname des Besitzers
   long price;//Preis
   boolean isNew;//neu oder nicht
   int placesInTheSalon;//Anzahl der Sitzplätze in der Kabine
   String salonMaterial;// Innenmaterial
   boolean insurance;//Ist es versichert?
   String manufacturerCountry;//Herstellungsland
   int trunkVolume;// Kofferraumvolumen
   int accelerationTo100km;//Beschleunigung auf 100 km/h in Sekunden


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

       System.out.println(„Modell Bugatti Veyron. Motorgröße –“ + bugatti.engineVolume + ", Stamm - " + bugatti.trunkVolume + „Der Salon besteht aus“ + bugatti.salonMaterial +
       ", Scheibenbreite - " + bugatti.wheels + ". Wurde 2018 von Herrn übernommen. " + bugatti.ownerLastName);

   }

}
Konsolenausgabe:
Bugatti Veyron-Modell. Hubraum - 6,3, Kofferraum - 0, Innenraum aus Null, Felgenbreite - 0. Wurde 2018 von Herrn Null gekauft
Ihr Käufer, der 2 Millionen Dollar für ein Auto bezahlt hat, wird es offensichtlich nicht mögen, „Mr. Null“ genannt zu werden! Aber im Ernst, am Ende hatte unser Programm ein falsch erstelltes Objekt – ein Auto mit der Felgenbreite 0 (also überhaupt keine Felgen), einem fehlenden Kofferraum, einem Innenraum aus unbekanntem Material und sogar einem unbekannten Objekt . Man kann sich nur vorstellen, wie ein solcher Fehler während der Ausführung des Programms auftreten kann! Wir müssen solche Situationen irgendwie vermeiden. Wir benötigen eine Einschränkung unseres Programms: Beim Erstellen eines neuen Fahrzeugobjekts müssen beispielsweise immer das Modell und die Höchstgeschwindigkeit dafür angegeben werden. Andernfalls lassen Sie die Objekterstellung nicht zu. Konstruktorfunktionen bewältigen diese Aufgabe problemlos. Sie haben ihren Namen aus einem bestimmten Grund erhalten. Der Konstruktor erstellt eine Art „Skelett“ der Klasse, dem jedes neue Objekt der Klasse entsprechen muss. Der Einfachheit halber kehren wir zu einer einfacheren Version der Car- Klasse mit zwei Feldern zurück. Aufgrund unserer Anforderungen sieht der Konstruktor für die Car- Klasse folgendermaßen aus:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
Und das Erstellen eines Objekts sieht jetzt so aus:
public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 407);
}
Passt aufwie der Konstruktor erstellt wird. Sie ähnelt einer regulären Methode, verfügt jedoch über keinen Rückgabetyp. In diesem Fall wird der Klassenname im Konstruktor ebenfalls mit einem Großbuchstaben angegeben. In unserem Fall - Auto . Darüber hinaus verwendet der Konstruktor das new-to-you-Schlüsselwort this . „this“ bedeutet auf Englisch „dies, dies“. Dieses Wort bezieht sich auf ein bestimmtes Objekt. Code im Konstruktor:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
lässt sich fast wörtlich übersetzen: „ Modell für diese Maschine (die wir gerade erstellen) = das Modellargument , das im Konstruktor angegeben ist. maxSpeed ​​​​für diese Maschine (die wir erstellen) = das maxSpeed- Argument , das wird im Konstruktor angegeben.“ Das ist, was passiert ist:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car("Bugatti Veyron", 407);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
Konsolenausgabe:
Bugatti Veyron 407
Der Konstruktor hat die erforderlichen Werte erfolgreich zugewiesen. Sie haben vielleicht bemerkt, dass ein Konstruktor einer regulären Methode sehr ähnlich ist! Das ist so: Ein Konstruktor ist eine Methode, nur ein wenig spezifisch :) Genau wie bei einer Methode haben wir Parameter an unseren Konstruktor übergeben. Und genau wie der Aufruf einer Methode funktioniert auch der Aufruf eines Konstruktors nicht, wenn Sie ihn nicht angeben:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car(); //Fehler!
   }

}
Sie sehen, der Designer hat getan, was wir erreichen wollten. Jetzt können Sie kein Auto ohne Geschwindigkeit oder ohne Modell erstellen! Die Ähnlichkeiten zwischen Konstruktoren und Methoden enden hier nicht. Genau wie Methoden können Konstruktoren überladen werden. Stellen Sie sich vor, Sie haben zwei Katzen zu Hause. Eines davon hast du als Kätzchen genommen, das zweite hast du als Erwachsener von der Straße nach Hause gebracht und weißt nicht genau, wie alt es ist. Das bedeutet, dass unser Programm in der Lage sein sollte, zwei Arten von Katzen zu erstellen – mit einem Namen und einem Alter für die erste Katze und nur mit einem Namen – für die zweite Katze. Dazu überladen wir den Konstruktor:
public class Cat {

   String name;
   int age;

   //für die erste Katze
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   //für die zweite Katze
   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
Zum ursprünglichen Konstruktor mit den Parametern „name“ und „age“ haben wir einen weiteren hinzugefügt, nur mit einem Namen. In den vorherigen Lektionen haben wir Methoden auf die gleiche Weise überladen. Jetzt können wir erfolgreich beide Versionen von Katzen erstellen :) Warum werden Konstrukteure benötigt?  - 2Erinnern Sie sich, dass wir zu Beginn der Vorlesung gesagt haben, dass Sie bereits Konstruktoren verwendet haben, es Ihnen aber einfach nicht aufgefallen ist? So ist das. Tatsache ist, dass jede Klasse in Java einen sogenannten Standardkonstruktor hat. Es hat keine Argumente, wird aber jedes Mal ausgelöst, wenn ein Objekt einer beliebigen Klasse erstellt wird.
public class Cat {

   public static void main(String[] args) {

       Cat barsik = new Cat(); //Hier hat der Standardkonstruktor gearbeitet
   }
}
Auf den ersten Blick fällt das nicht auf. Nun, wir haben ein Objekt erstellt und es erstellt. Wo ist die Arbeit des Designers? Um dies zu sehen, schreiben wir mit unseren eigenen Händen einen leeren Konstruktor für die Cat- Klasse und geben darin einen Satz an die Konsole aus. Wenn es angezeigt wird, hat der Konstruktor funktioniert.
public class Cat {

   public Cat() {
       System.out.println(„Eine Katze erschaffen!“);
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(); //Hier hat der Standardkonstruktor gearbeitet
   }
}
Konsolenausgabe:
Sie haben eine Katze erschaffen!
Hier ist die Bestätigung! Der Standardkonstruktor ist in Ihren Klassen immer unsichtbar vorhanden. Aber Sie müssen noch eine weitere Funktion kennen. Der Standardkonstruktor verschwindet aus der Klasse, wenn Sie einen Konstruktor mit Argumenten erstellen. Den Beweis dafür haben wir tatsächlich bereits oben gesehen. Hier in diesem Code:
public class Cat {

   String name;
   int age;

   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(); //Fehler!
   }
}
Wir konnten keine Katze ohne Namen und Alter erstellen, da wir einen Konstruktor für Cat definiert haben : Zeichenfolge + Nummer. Der Standardkonstruktor verschwand unmittelbar danach aus der Klasse. Denken Sie daher unbedingt daran: Wenn Sie in Ihrer Klasse mehrere Konstruktoren benötigen, einschließlich eines leeren, müssen Sie diesen separat erstellen. Wir erstellen zum Beispiel ein Programm für eine Tierklinik. Unsere Klinik möchte Gutes tun und obdachlosen Katzen helfen, deren Namen und Alter wir nicht kennen. Dann sollte unser Code so aussehen:
public class Cat {

   String name;
   int age;

   //für Hauskatzen
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   //für Straßenkatzen
   public Cat() {
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5);
       Cat streetCat = new Cat();
   }
}
Nachdem wir nun explizit einen Standardkonstruktor geschrieben haben, können wir Katzen beider Typen erstellen :) Für einen Konstruktor (wie für jede Methode) ist die Reihenfolge der Argumente sehr wichtig. Lassen Sie uns die Namens- und Altersargumente in unserem Konstruktor vertauschen.
public class Cat {

   String name;
   int age;

   public Cat(int age, String name) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(„Barsik“, 10); //Fehler!
   }
}
Fehler! Der Konstruktor gibt eindeutig an, dass beim Erstellen eines Cat-Objekts ihm eine Zahl und eine Zeichenfolge in dieser Reihenfolge übergeben werden müssen. Deshalb funktioniert unser Code nicht. Denken Sie unbedingt daran und denken Sie daran, wenn Sie Ihre eigenen Klassen erstellen:
public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Das sind zwei völlig unterschiedliche Designer! Wenn wir die Antwort auf die Frage „Warum brauchen wir einen Konstruktor?“ in einem Satz ausdrücken, können wir sagen: Damit Objekte immer im richtigen Zustand sind. Wenn Sie Konstruktoren verwenden, werden alle Ihre Variablen korrekt initialisiert und es gibt keine Autos mit Geschwindigkeit 0 oder andere „falsche“ Objekte im Programm. Ihr Einsatz ist vor allem für den Programmierer selbst von großem Nutzen. Wenn Sie die Felder selbst initialisieren, besteht ein hohes Risiko, etwas zu übersehen und einen Fehler zu machen. Bei einem Konstruktor passiert das jedoch nicht: Wenn Sie ihm nicht alle erforderlichen Argumente übergeben oder deren Typen verwechselt haben, gibt der Compiler sofort einen Fehler aus. Es ist gesondert zu erwähnen, dass Sie die Logik Ihres Programms nicht in den Konstruktor einfügen sollten. Hierzu stehen Ihnen Methoden zur Verfügung, mit denen Sie alle benötigten Funktionalitäten beschreiben können. Schauen wir uns an, warum Konstruktorlogik eine schlechte Idee ist:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println(„Unsere Autofabrik heißt“ + this.name);
   System.out.println(„Sie wurde gegründet“ + this.age + " Jahre zuvor" );
   System.out.println(„In dieser Zeit wurde es produziert“ + this.carsCount +  "Autos");
   System.out.println(„Im Durchschnitt produziert sie“ + (this.carsCount/this.age) + „Autos pro Jahr“);
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
Wir haben eine CarFactory- Klasse , die eine Fabrik zur Herstellung von Autos beschreibt. Im Konstruktor initialisieren wir alle Felder und platzieren die Logik hier: Wir zeigen einige Informationen über die Fabrik auf der Konsole an. Es scheint, dass daran nichts auszusetzen ist, das Programm hat perfekt funktioniert. Konsolenausgabe:
Unsere Autofabrik heißt Ford. Sie wurde vor 115 Jahren gegründet. In dieser Zeit wurden 50.000.000 Autos produziert. Im Durchschnitt werden 434.782 Autos pro Jahr produziert.
Aber tatsächlich haben wir eine Zeitbombe gelegt. Und solcher Code kann sehr leicht zu Fehlern führen. Stellen wir uns vor, wir sprechen jetzt nicht von Ford, sondern von der neuen Fabrik „Amigo Motors“, die seit weniger als einem Jahr existiert und 1000 Autos produziert hat:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println(„Unsere Autofabrik heißt“ + this.name);
   System.out.println(„Sie wurde gegründet“ + this.age + " Jahre zuvor" );
   System.out.println(„In dieser Zeit wurde es produziert“ + this.carsCount +  "Autos");
   System.out.println(„Im Durchschnitt produziert sie“ + (this.carsCount/this.age) + „Autos pro Jahr“);
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
Konsolenausgabe:
Unsere Autofabrik heißt Amigo Motors Exception im Thread „main“ java.lang.ArithmeticException: / by Zero. Sie wurde vor 0 Jahren gegründet. Während dieser Zeit produzierte sie 1000 Autos bei CarFactory.<init>(CarFactory.java:15) bei CarFactory.main(CarFactory.java:23) Prozess mit Exit-Code 1 beendet</init>
Wir sind angekommen! Das Programm endete mit einem seltsamen Fehler. Versuchen Sie zu erraten, was der Grund ist? Der Grund ist die Logik, die wir im Konstruktor platziert haben. Konkret in dieser Zeile:
System.out.println(„Im Durchschnitt produziert sie“ + (this.carsCount/this.age) + „Autos pro Jahr“);
Hier führen wir die Berechnung durch und dividieren die Anzahl der produzierten Autos durch das Alter der Fabrik. Und da unsere Fabrik neu ist (also 0 Jahre alt), ist das Ergebnis eine Division durch 0, was in der Mathematik verboten ist. Infolgedessen bricht das Programm mit einem Fehler ab. Was hätten wir tun sollen? Verschieben Sie die gesamte Logik in eine separate Methode und nennen Sie sie beispielsweise printFactoryInfo() . Sie können ihm ein CarFactory- Objekt als Parameter übergeben . Sie können dort auch die gesamte Logik unterbringen und gleichzeitig mögliche Fehler wie unseren mit Nulljahren verarbeiten. Jedem das Seine. Konstruktoren werden benötigt, um den Zustand eines Objekts korrekt festzulegen. Für die Geschäftslogik haben wir Methoden. Man sollte das eine nicht miteinander vermischen.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION