CodeGym/Java blog/Véletlen/Java konstruktorok
John Squirrels
Szint
San Francisco

Java konstruktorok

Megjelent a csoportban
Szia! Ma egy nagyon fontos témával foglalkozunk, amely tárgyainkat érinti. Túlzás nélkül kijelenthetjük, hogy ezt a témát minden nap használni fogod a való életben! Java konstruktorokról beszélünk. Lehet, hogy most hallja először ezt a kifejezést, de valójában már használt konstruktorokat. Csak nem vetted észre :) Erről később meggyőzzük magunkat.

Mik a világban a konstruktőrök, és miért van rájuk szükség?

Nézzünk két példát.
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

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

   }
}
Megalkottuk az autónkat, beállítottuk a modelljét és a maximális sebességét. De az Autó objektumnak nyilván nem lenne 2 mezője egy valós projektben. Például lehet, hogy 16 mezőből áll!
public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   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.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

   }

}
Létrehoztunk egy új Autó objektumot. Egy probléma van: 16 mezőnk van, de csak 12-t inicializáltunk ! Nézze meg most a kódot, és próbálja meg megtalálni azokat a mezőket, amelyeket elfelejtettünk! Nem olyan egyszerű, mi? Ebben a helyzetben a programozó könnyen hibázhat, és nem inicializál néhány mezőt. Ennek eredményeként a program helytelenül fog működni:
public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   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.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model: Bugatti Veyron. Engine volume: " + bugatti.engineVolume + ". Trunk volume: " + bugatti.trunkVolume + ". Cabin material: " + bugatti.cabinMaterial +
       ". Wheel width: " + bugatti.wheels + ". Purchased in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
Konzol kimenet: Modell: Bugatti Veyron. Motortérfogat: 6.3. Csomagtér térfogata: 0. Fülke anyaga: null. Kerékszélesség: 0. 2018-ban vásárolta Mr. null Az Ön vevője, aki 2 millió dollárt mondott le az autóért, nyilvánvalóan nem fogja szeretni, ha " Mr. null "-nak hívják! De komolyra fordítva a szót, a lényeg az, hogy programunk hibásan hozott létre egy objektumot: 0-ás kerékszélességű autót (vagyis kerekek nélkül), hiányzó csomagtartót, ismeretlen anyagból készült kabint és mindenekelőtt meghatározatlan tulajdonost. . El tudod képzelni, hogy egy ilyen hiba hogyan tud "elszállni" a program futása közben! Valahogy el kell kerülnünk az ilyen helyzeteket. Korlátoznunk kell a programunkat: új Autó készítésekorobjektum esetén azt szeretnénk, hogy a mezők, például a modell és a maximális sebesség mindig meg legyenek adva. Ellenkező esetben meg akarjuk akadályozni az objektum létrehozását. A kivitelezők könnyedén kezelik ezt a feladatot. Okkal kapták a nevüket. A konstruktor egyfajta osztály "csontvázat" hoz létre, amelyhez minden új objektumnak meg kell felelnie. A kényelem kedvéért térjünk vissza a Car osztály egyszerűbb, két mezős változatához. Igényeinket figyelembe véve a Car osztály kivitelezője így fog kinézni:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}

// And creating an object now looks like this:

public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 378);
}
Jegyezze meg, hogyan deklarálják a konstruktort. Hasonló egy hagyományos metódushoz, de nincs visszatérési típusa. Ezenkívül a konstruktor nagybetűvel kezdődően adja meg az osztály nevét ( Car ). Ezenkívül a konstruktor egy új kulcsszóval használatos az Ön számára: ez . Ez a kulcsszó egy adott objektum jelzésére szolgál. A kód a konstruktorban
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
szinte szó szerint értelmezhető: "Ennek az autónak a modellje (amelyet most készítünk) a modell argumentuma, amelyet a konstruktőrnek továbbítanak. A maxSpeed ​​ehhez az autóhoz (amelyet létrehozunk) a maxSpeed ​​argumentum, amelyet az konstruktőr." És csak ez történik:
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", 378);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
Konzol kimenet: Bugatti Veyron 378 A konstruktor helyesen rendelte hozzá a szükséges értékeket. Talán észrevetted, hogy a konstruktor nagyon hasonlít egy közönséges metódushoz! Így van. A konstruktor valójában egy metódus, de sajátos tulajdonságokkal :) Csakúgy, mint a metódusoknál, itt is argumentumokat adtunk át a konstruktorunknak. És csakúgy, mint a metódusok meghívása, a konstruktorok meghívása sem fog működni, hacsak nem adja meg őket:
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(); // Error!
   }

}
Látható, hogy a kivitelező teljesíti, amit mi próbáltunk elérni. Most már nem lehet autót létrehozni sebesség vagy modell nélkül! A konstruktorok és a metódusok hasonlósága itt nem ér véget. A metódusokhoz hasonlóan a konstruktorok is túlterhelhetők. Képzeld el, hogy van otthon 2 kismacska. Az egyiket cicaként kaptad. De a második, amit az utcáról vettél be, amikor már megnőtt, és nem tudod pontosan, hány éves. Ebben az esetben azt szeretnénk, hogy programunk kétféle macskát tudjon létrehozni: névvel és életkorú macskát (az első macskának), és csak névvel rendelkező macskát (a második macskának). Ehhez túlterheljük a konstruktort:
public class Cat {

   String name;
   int age;

   // For the first cat
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For the second cat
   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
Az eredeti "name" és "age" paraméterekkel rendelkező konstruktor mellé hozzáadtunk még egyet csak név paraméterrel. Pontosan ugyanúgy, ahogy az előző leckéken túlterheltük a módszereket. Most már mindkét fajta macskát létrehozhatjuk :)
Miért van szükségünk kivitelezőkre?  - 2
Emlékszel, hogy az óra elején azt mondtuk, hogy már használtál konstruktorokat anélkül, hogy észrevetted volna? Komolyan gondoltuk, amit mondtunk. A tény az, hogy a Java-ban minden osztály rendelkezik úgynevezett alapértelmezett konstruktorral. Nem igényel argumentumot, de minden alkalommal meghívódik, amikor létrehoz egy objektumot bármely osztályból.
public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Első pillantásra láthatatlan. Létrehoztunk egy tárgyat, és mi van? Hol csinál itt valamit a kivitelező? Ennek megtekintéséhez írjunk egy üres konstruktort a Cat osztályhoz. Megjelenítünk benne néhány kifejezést. Ha a kifejezés megjelenik, akkor a konstruktor meghívásra került.
public class Cat {

   public Cat() {
       System.out.println("A cat has been created!");
   }

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Konzol kimenet: Egy macska létrejött! Itt a megerősítés! Az alapértelmezett konstruktor mindig láthatatlanul jelen van az osztályokban. De még egy dolgot tudnod kell róla. Az alapértelmezett konstruktor kikerül az osztályból, miután létrehoz egy konstruktort argumentumokkal. Valójában a fentiekben már láttuk ennek bizonyítékát. Ebben a kódban volt:
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 smudge = new Cat(); //Error!
   }
}
Név és életkor nélkül nem tudtunk Cat -et létrehozni, mert egy Cat konstruktort deklaráltunk string és int paraméterekkel. Emiatt az alapértelmezett konstruktor azonnal eltűnt az osztályból. Ezért ügyeljen arra, hogy ha több konstruktorra van szüksége az osztályban, beleértve egy argumentum nélküli konstruktort is, akkor azt külön kell deklarálnia. Tegyük fel például, hogy programot készítünk egy állatorvosi klinika számára. Rendelőnk jót akar tenni és segíteni olyan hajléktalan cicáknak, akiknek a neve és életkora ismeretlen. Akkor a kódunknak így kell kinéznie:
public class Cat {

   String name;
   int age;

   // For cats with owners
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCat = new Cat();
   }
}
Most, hogy írtunk egy explicit alapértelmezett konstruktort, mindkét típusú macskát létrehozhatjuk :) Mint minden módszernél, itt is nagyon fontos a konstruktornak átadott argumentumok sorrendje. Cseréljük fel a név és az életkor paramétereit a konstruktorunkban.
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 smudge = new Cat("Smudge", 10); // Error!
   }
}
Egy hiba! A konstruktor egyértelműen előírja, hogy a Cat objektum létrehozásakor egy számot és egy karakterláncot kell átadni, ebben a sorrendben. Tehát a kódunk nem működik. Ügyeljen erre, és tartsa szem előtt, amikor bejelenti saját osztályait:
public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Ez két teljesen különböző konstruktőr! Ha egyetlen mondatban adnánk meg a választ a „Miért van szükségem konstruktorra?” kérdésre, azt mondhatnánk: „Hogy biztosítsuk, hogy az objektumok mindig érvényes állapotúak legyenek”. Konstruktorok használatakor az összes változó helyesen inicializálódik. A programjaiban nem lesznek 0 sebességű autók vagy más "érvénytelen" objektumok. Fő előnyük a programozó számára. Ha kézzel inicializálja a mezőket (egy objektum létrehozása után), nagy a kockázata annak, hogy valamit kihagy, és hibát okoz. De ez nem történik meg konstruktorral: ha nem adjuk át az összes szükséges argumentumot, vagy rossz típusú argumentumokat adunk meg, a fordító azonnal hibát regisztrál. Azt is külön meg kell mondanunk, hogy ne tegye fel a programját. s logika egy konstruktor belsejében. Erre valók a módszerek. A módszerekben meg kell határoznia az összes szükséges funkciót. Nézzük meg, miért rossz ötlet logikát adni egy konstruktorhoz:
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("Our car factory is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
Van egy CarFactory osztályunk, amely leírja az autógyárat. A konstruktoron belül inicializáljuk az összes mezőt, és beépítünk némi logikát: megjelenítünk néhány információt a gyárról. Úgy tűnik, nincs ebben semmi rossz. A program jól működik. Konzol teljesítmény: Autógyárunkat Fordnak hívják. 115 éve alapították Azóta 50000000 autót gyártott Átlagosan 434782 autót évente, de valójában egy késleltetett bányát raktunk le. És ez a fajta kód nagyon könnyen hibákhoz vezethet. Tegyük fel, hogy most nem a Fordról beszélünk, hanem egy új "Amigo Motors" gyárról, amely kevesebb mint egy éve létezik, és 1000 autót gyártott:
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("Our car factor is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
Konzol kimenet: Autógyárunk az Amigo Motors Exception neve a "main" szálban java.lang.ArithmeticException: / by zero Alapítása 0 éve Azóta 1000 autót gyártott a CarFactory-ban. (CarFactory.java:15) itt: CarFactory.main(CarFactory.java:23) A folyamat az 1-es kilépési kóddal befejeződött Bumm! A program valamiféle érthetetlen hibával ér véget. Megpróbálnád kitalálni az okot? A probléma a konstruktorba bevitt logikában van. Pontosabban ez a sor:
System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Itt egy számítást végez, és elosztja a gyártott autók számát a gyár életkorával. És mivel a gyárunk új (azaz 0 éves), elosztjuk 0-val, amit matekból nem tudunk megcsinálni. Következésképpen a program hibával leáll.

Mit kellett volna tennünk?

Tedd az összes logikát egy külön metódusba. Nevezzük printFactoryInfo() -nak . Átadhat neki egy CarFactory objektumot argumentumként. Az összes logikát odahelyezheti, és ezzel egyidejűleg kezelheti a lehetséges hibákat (például a miénket, amely nulla évet érint). Mindenkinek a magáét. Konstruktorokra van szükség az objektum érvényes állapotának beállításához. Vannak módszereink az üzleti logikára. Ne keverje egyiket a másikkal. A tanultak megerősítése érdekében javasoljuk, hogy nézzen meg egy videóleckét a Java-tanfolyamról
Hozzászólások
  • Népszerű
  • Új
  • Régi
Hozzászólás írásához be kell jelentkeznie
Ennek az oldalnak még nincsenek megjegyzései