CodeGym /Blog Java /Aleatoriu /Constructori Java
John Squirrels
Nivel
San Francisco

Constructori Java

Publicat în grup
Bună! Astăzi vom lua în considerare un subiect foarte important care privește obiectele noastre. Fără a exagera, putem spune că vei folosi acest subiect în viața reală în fiecare zi! Vorbim despre constructori Java. Aceasta poate fi prima dată când auziți acest termen, dar de fapt ați folosit deja constructori. Pur si simplu nu ti-ai dat seama :) Ne convingem de asta mai tarziu.

Ce sunt constructorii și de ce sunt necesari ei?

Să luăm în considerare două exemple.

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

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

   }
}
Am creat mașina noastră și i-am stabilit modelul și viteza maximă. Dar obiectul Car , evident, nu ar avea 2 câmpuri într-un proiect real. De exemplu, ar putea avea 16 câmpuri!

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";

   }

}
Am creat un nou obiect Car . Există o problemă: avem 16 câmpuri, dar am inițializat doar 12 ! Priviți codul acum și încercați să găsiți câmpurile pe care le-am uitat! Nu atât de ușor, nu? În această situație, un programator poate face cu ușurință o greșeală și nu poate inițializa un câmp. Ca urmare, programul se va comporta incorect:

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);

   }

}
Ieșire consolă: Model: Bugatti Veyron. Volumul motorului: 6.3. Volumul portbagajului: 0. Material cabină: nul. Lățimea roții: 0. Achiziționat în 2018 de domnul null Cumpărătorul dvs., care a renunțat la 2 milioane de dolari pentru mașină, evident că nu va plăcea să fie numit „ dl nul ”! Dar serios, concluzia este că programul nostru a creat un obiect incorect: o mașină cu lățimea roților de 0 (adică fără roți), un portbagaj lipsă, o cabină dintr-un material necunoscut și, mai presus de toate, un proprietar nedefinit. . Vă puteți imagina doar cum se poate „dezactiva” o astfel de greșeală când programul rulează! Trebuie să evităm cumva astfel de situații. Trebuie să ne limităm programul: când creăm o mașină nouăobiect, dorim ca câmpurile, cum ar fi modelul și viteza maximă, să fie întotdeauna specificate. În caz contrar, dorim să împiedicăm crearea obiectului. Constructorii se ocupă de această sarcină cu ușurință. Și-au primit numele pentru un motiv. Constructorul creează un fel de „schelet” de clasă cu care fiecare obiect nou trebuie să se potrivească. Pentru comoditate, să revenim la versiunea mai simplă a clasei Car cu două câmpuri. Având în vedere cerințele noastre, constructorul clasei Car va arăta astfel:

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);
}
Observați cum este declarat un constructor. Este similar cu o metodă obișnuită, dar nu are un tip de returnare. Mai mult, constructorul specifică numele clasei ( Car ) începând cu o literă mare. În plus, constructorul este folosit cu un cuvânt cheie care este nou pentru tine: this . Cuvântul cheie this este pentru a indica un anumit obiect. Codul din constructor

public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
poate fi interpretat aproape literal: „ Modelul pentru această mașină (cea pe care o creăm acum) este argumentul modelului transmis constructorului. MaxSpeed ​​pentru această mașină (cea pe care o creăm) este argumentul maxSpeed ​​transmis către constructor. constructor." Și tocmai asta se întâmplă:

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);
   }

}
Ieșire consolă: Bugatti Veyron 378 Constructorul a atribuit corect valorile necesare. Poate ați observat că un constructor este foarte asemănător cu o metodă obișnuită! Deci este. Un constructor este într-adevăr o metodă, dar cu caracteristici specifice :) La fel ca în cazul metodelor, am transmis argumente constructorului nostru. Și la fel ca apelarea unei metode, apelarea unui constructor nu va funcționa decât dacă le specificați:

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!
   }
  
}
Puteți vedea că constructorul realizează ceea ce încercam să realizăm. Acum nu poți crea o mașină fără viteză sau model! Asemănarea dintre constructori și metode nu se termină aici. La fel ca și metodele, constructorii pot fi supraîncărcați. Imaginați-vă că aveți 2 pisici de companie acasă. Ai unul dintre ei ca pisoi. Dar pe al doilea l-ai luat de pe stradă când era deja crescut și nu știi exact câți ani are. În acest caz, dorim ca programul nostru să poată crea două tipuri de pisici: cele cu nume și vârstă (pentru prima pisică) și cele cu doar un nume (pentru a doua pisică). Pentru aceasta, vom supraîncărca constructorul:

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");
   }

}
Pe lângă constructorul original cu parametrii „nume” și „vârstă”, am adăugat încă unul cu doar un parametru de nume. Exact în același mod în care am supraîncărcat metodele în lecțiile anterioare. Acum putem crea ambele tipuri de pisici :)
De ce avem nevoie de constructori?  - 2
Vă amintiți că la începutul lecției am spus că ați folosit deja constructori fără să vă dați seama? Am vrut să spunem ceea ce am spus. Faptul este că fiecare clasă din Java are ceea ce se numește un constructor implicit. Nu ia niciun argument, dar este invocat de fiecare dată când creați orice obiect din orice clasă.

public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
La prima vedere, este invizibil. Am creat un obiect, deci ce? Unde face constructorul ceva aici? Pentru a-l vedea, să scriem în mod explicit un constructor gol pentru clasa Cat . Vom afișa o frază în interiorul ei. Dacă expresia este afișată, atunci constructorul a fost invocat.

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
   }
}
Ieșire din consolă: a fost creată o pisică! Acolo este confirmarea! Constructorul implicit este întotdeauna prezent invizibil în clasele dvs. Dar trebuie să mai știi un lucru despre asta. Constructorul implicit este eliminat dintr-o clasă odată ce creați un constructor cu argumente. De fapt, am văzut deja dovezi în acest sens mai sus. Era in acest cod:

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!
   }
}
Nu am putut crea un Cat fără nume și vârstă, deoarece am declarat un constructor Cat cu parametri string și int . Acest lucru a făcut ca constructorul implicit să dispară imediat din clasă. Așadar, asigurați-vă că rețineți că dacă aveți nevoie de mai mulți constructori în clasa dvs., inclusiv un constructor fără argument, va trebui să-l declarați separat. De exemplu, să presupunem că creăm un program pentru o clinică veterinară. Clinica noastră vrea să facă fapte bune și să ajute pisoi fără adăpost ale căror nume și vârste nu sunt cunoscute. Atunci codul nostru ar trebui să arate astfel:

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();
   }
}
Acum că am scris un constructor implicit explicit, putem crea ambele tipuri de pisici :) Ca în cazul oricărei metode, ordinea argumentelor transmise unui constructor este foarte importantă. Să schimbăm argumentele nume și vârstă în constructorul nostru.

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!
   }
}
O eroare! Constructorul stipulează clar că atunci când un obiect Cat este creat, trebuie să i se transmită un număr și un șir, în această ordine. Deci, codul nostru nu funcționează. Asigurați-vă că rețineți acest lucru și țineți minte atunci când vă declarați propriile cursuri:

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

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Aceștia sunt doi constructori total diferiți! Dacă ar fi să exprimăm într-o singură propoziție răspunsul la întrebarea „De ce am nevoie de un constructor?”, am putea spune „Pentru a ne asigura că obiectele au întotdeauna o stare validă”. Când utilizați constructori, toate variabilele dvs. vor fi inițializate corect. Programele dvs. nu vor avea mașini cu o viteză de 0 sau alte obiecte „invalide”. Principalul lor beneficiu este pentru programator. Dacă inițializați câmpurile manual (după crearea unui obiect), există un mare risc să pierdeți ceva și să introduceți o eroare. Dar acest lucru nu se va întâmpla cu un constructor: dacă nu reușiți să treceți toate argumentele necesare sau dacă treceți tipurile greșite de argumente, compilatorul va înregistra imediat o eroare. De asemenea, trebuie să spunem separat că nu ar trebui să vă puneți programul' logica din interiorul unui constructor. Pentru asta sunt metodele. Metodele sunt acolo unde ar trebui să definiți toate funcționalitățile necesare. Să vedem de ce adăugarea de logică la un constructor este o idee proastă:

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);
   }
}
Avem o clasă CarFactory care descrie fabrica de mașini. În interiorul constructorului, inițializam toate câmpurile și includem ceva logică: afișăm câteva informații despre fabrică. Se pare că nu e nimic rău în asta. Programul funcționează bine. Ieșire din consolă: Fabrica noastră de mașini se numește Ford. A fost înființată acum 115 ani De atunci, a produs 50000000 de mașini În medie, produce 434782 de mașini pe an. Dar de fapt am pus o mină întârziată. Și acest tip de cod poate duce foarte ușor la erori. Să presupunem că acum nu vorbim despre Ford, ci despre o nouă fabrică numită „Amigo Motors”, care există de mai puțin de un an și a produs 1000 de mașini:

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);
   }
}
Ieșire consolă: Fabrica noastră de mașini se numește Amigo Motors Exception în firul „principal” java.lang.ArithmeticException: / by zero A fost fondată acum 0 ani De atunci, a produs 1000 de mașini la CarFactory. (CarFactory.java:15) la CarFactory.main(CarFactory.java:23) Procesul s-a încheiat cu codul de ieșire 1 Bum! Programul se termină cu un fel de eroare de neînțeles. Poti incerca sa ghicesti cauza? Problema este în logica pe care am introdus-o în constructor. Mai precis, această linie:

System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Aici efectuați un calcul și împărțiți numărul de mașini produse la vârsta fabricii. Și întrucât fabrica noastră este nouă (adică are 0 ani), împărțim la 0, ceea ce nu putem face la matematică. În consecință, programul se încheie cu o eroare.

Ce ar fi trebuit să facem?

Pune toată logica într-o metodă separată. Să-i numim printFactoryInfo() . Puteți să îi transmiteți un obiect CarFactory ca argument. Puteți pune toată logica acolo și, în același timp, puteți gestiona potențialele erori (cum ar fi a noastră care implică zero ani). Fiecare a lui. Sunt necesari constructori pentru a seta starea validă a obiectului. Avem metode pentru logica de afaceri. Nu amestecați unul cu celălalt. Pentru a consolida ceea ce ați învățat, vă sugerăm să urmăriți o lecție video de la Cursul nostru Java
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION