CodeGym /Java-blogg /Tilfeldig /Java-konstruktører
John Squirrels
Nivå
San Francisco

Java-konstruktører

Publisert i gruppen
Hei! I dag skal vi vurdere et veldig viktig tema som angår objektene våre. Uten å overdrive kan vi si at du kommer til å bruke dette emnet i det virkelige liv hver dag! Vi snakker om Java Constructors. Dette kan være første gang du hører dette begrepet, men du har faktisk allerede brukt konstruktører. Du skjønte det bare ikke :) Vi overbeviser oss selv om dette senere.

Hva i all verden er konstruktører og hvorfor trengs de?

La oss vurdere to eksempler.

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

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

   }
}
Vi skapte bilen vår, og satte modell og maksimal hastighet. Men Bilobjektet ville åpenbart ikke ha 2 felt i et reelt prosjekt. Den kan for eksempel ha 16 felt!

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

   }

}
Vi har opprettet et nytt bilobjekt . Det er ett problem: vi har 16 felt, men vi initialiserte bare 12 ! Se på koden nå og prøv å finne feltene vi har glemt! Ikke så lett, hva? I denne situasjonen kan en programmerer lett gjøre en feil og unnlate å initialisere et felt. Som et resultat vil programmet oppføre seg feil:

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

   }

}
Konsollutgang: Modell: Bugatti Veyron. Motorvolum: 6,3. Bagasjeromsvolum: 0. Hyttemateriale: null. Hjulbredde: 0. Kjøpt i 2018 av Mr. null Kjøperen din, som ga fra seg 2 millioner dollar for bilen, vil åpenbart ikke like å bli kalt " Mr. null "! Men seriøst, poenget er at programmet vårt opprettet et objekt feil: en bil med en hjulbredde på 0 (dvs. ingen hjul i det hele tatt), en manglende bagasjerom, en hytte laget av et ukjent materiale, og fremfor alt en udefinert eier . Du kan bare forestille deg hvordan en slik feil kan "gå av" når programmet kjører! Vi må på en eller annen måte unngå slike situasjoner. Vi må begrense programmet vårt: når vi lager en ny bilobjekt, vil vi at feltene, som modell og maksimal hastighet, alltid skal spesifiseres. Ellers ønsker vi å forhindre opprettelsen av objektet. Konstruktører håndterer denne oppgaven med letthet. De har fått navnet sitt av en grunn. Konstruktøren lager et slags klasse "skjelett" som hvert nytt objekt må matche. For enkelhets skyld, la oss gå tilbake til den enklere versjonen av bilklassen med to felt. Med tanke på våre krav, vil bilklassens konstruktør se slik ut:

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);
}
Legg merke til hvordan en konstruktør er deklarert. Den ligner på en vanlig metode, men den har ingen returtype. Dessuten spesifiserer konstruktøren klassenavnet ( Bil ) som starter med en stor bokstav. I tillegg brukes konstruktøren med et nøkkelord som er nytt for deg: dette . Nøkkelordet dette er for å indikere et bestemt objekt. Koden i konstruktøren

public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
kan tolkes nesten ordrett: "Modellen for denne bilen (den vi lager nå) er modellargumentet som sendes til konstruktøren. maxSpeed ​​for denne bilen (den vi lager) er maxSpeed- argumentet som sendes til konstruktør." Og det er bare det som skjer:

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

}
Konsollutgang: Bugatti Veyron 378 Konstruktøren tilordnet de nødvendige verdiene riktig. Du har kanskje lagt merke til at en konstruktør er veldig lik en vanlig metode! Sånn er det. En konstruktør er egentlig en metode, men med spesifikke funksjoner :) Akkurat som med metoder, ga vi argumenter til konstruktøren vår. Og akkurat som å kalle en metode, vil ikke kalle en konstruktør fungere med mindre du spesifiserer dem:

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!
   }
  
}
Du kan se at konstruktøren oppnår det vi prøvde å oppnå. Nå kan du ikke lage en bil uten hastighet eller modell! Likheten mellom konstruktører og metoder slutter ikke her. Akkurat som metoder, kan konstruktører bli overbelastet. Tenk deg at du har 2 kjæledyrkatter hjemme. Du fikk en av dem som kattunge. Men den andre tok du inn fra gaten da den allerede var voksen, og du vet ikke nøyaktig hvor gammel den er. I dette tilfellet ønsker vi at programmet vårt skal kunne lage to typer katter: de med navn og alder (for den første katten), og de med bare et navn (for den andre katten). For dette vil vi overbelaste konstruktøren:

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

}
I tillegg til den opprinnelige konstruktøren med "navn" og "alder" parametere, la vi til en til med bare en navneparameter. På nøyaktig samme måte som vi overbelastet metoder i tidligere leksjoner. Nå kan vi lage begge typer katter :)
Hvorfor trenger vi konstruktører?  - 2
Husk at vi i begynnelsen av leksjonen sa at du allerede har brukt konstruktører uten å være klar over det? Vi mente det vi sa. Faktum er at hver klasse i Java har det som kalles en standard konstruktør. Det krever ingen argumenter, men det påkalles hver gang du oppretter et objekt av en klasse.

public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Ved første øyekast er det usynlig. Vi laget et objekt, så hva? Hvor gjør konstruktøren noe her? For å se det, la oss eksplisitt skrive en tom konstruktør for Cat- klassen. Vi vil vise en setning i den. Hvis setningen vises, ble konstruktøren påkalt.

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
   }
}
Konsollutgang: En katt er opprettet! Der er bekreftelsen! Standardkonstruktøren er alltid usynlig til stede i klassene dine. Men du må vite en ting til om det. Standardkonstruktøren blir eliminert fra en klasse når du oppretter en konstruktør med argumenter. Faktisk har vi allerede sett bevis på dette ovenfor. Det sto i denne koden:

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!
   }
}
Vi kunne ikke lage en Cat uten navn og alder, fordi vi erklærte en Cat- konstruktør med streng- og int- parametere. Dette førte til at standardkonstruktøren umiddelbart forsvant fra klassen. Så husk at hvis du trenger flere konstruktører i klassen din, inkludert en konstruktør uten argumenter, må du deklarere det separat. Anta for eksempel at vi lager et program for en veterinærklinikk. Klinikken vår ønsker å gjøre gode gjerninger og hjelpe hjemløse kattunger hvis navn og alder er ukjent. Da skal koden vår se slik ut:

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();
   }
}
Nå som vi har skrevet en eksplisitt standardkonstruktør, kan vi lage begge typer katter :) Som med alle metoder er rekkefølgen på argumentene som sendes til en konstruktør veldig viktig. La oss bytte navn og aldersargumenter i konstruktøren vår.

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!
   }
}
En feil! Konstruktøren fastsetter tydelig at når et Cat- objekt opprettes, må det sendes et tall og en streng, i denne rekkefølgen. Så koden vår fungerer ikke. Husk å huske dette og ha det i bakhodet når du erklærer dine egne klasser:

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

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Dette er to helt forskjellige konstruktører! Hvis vi i en enkelt setning skulle uttrykke svaret på spørsmålet "Hvorfor trenger jeg en konstruktør?", kan vi si: "For å sikre at objekter alltid har en gyldig tilstand". Når du bruker konstruktører, vil alle variablene dine bli korrekt initialisert. Programmene dine vil ikke ha noen biler med en hastighet på 0 eller andre "ugyldige" objekter. Hovedfordelen deres er for programmereren. Hvis du initialiserer felt manuelt (etter å ha opprettet et objekt), er det stor risiko for at du går glipp av noe og introduserer en feil. Men dette vil ikke skje med en konstruktør: hvis du ikke klarer å sende alle de nødvendige argumentene eller du sender feil typer argumenter, vil kompilatoren umiddelbart registrere en feil. Vi må også si separat at du ikke bør legge programmet ditt' s logikk inne i en konstruktør. Det er dette metodene er til for. Metoder er der du bør definere all nødvendig funksjonalitet. La oss se hvorfor det er en dårlig idé å legge til logikk i en konstruktør:

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);
   }
}
Vi har en CarFactory -klasse som beskriver bilfabrikken. Inne i konstruktøren initialiserer vi alle feltene og inkluderer litt logikk: vi viser litt informasjon om fabrikken. Det virker som det ikke er noe dårlig med dette. Programmet fungerer fint. Konsollproduksjon: Bilfabrikken vår heter Ford Den ble grunnlagt for 115 år siden Siden den gang har den produsert 50000000 biler I gjennomsnitt produserer den 434782 biler per år. Men vi har faktisk lagt en forsinket gruve. Og denne typen kode kan veldig lett føre til feil. Anta at vi nå ikke snakker om Ford, men om en ny fabrikk kalt "Amigo Motors", som har eksistert i mindre enn ett år og har produsert 1000 biler:

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);
   }
}
Konsollutgang: Bilfabrikken vår heter Amigo Motors Unntak i tråden "hoved" java.lang.ArithmeticException: / med null Den ble grunnlagt for 0 år siden Siden den gang har den produsert 1000 biler hos CarFactory. (CarFactory.java:15) på CarFactory.main(CarFactory.java:23) Prosessen fullført med utgangskode 1 Bom! Programmet ender med en slags uforståelig feil. Kan du prøve å gjette årsaken? Problemet ligger i logikken vi legger inn i konstruktøren. Mer spesifikt, denne linjen:

System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Her utfører du en beregning og deler antall produserte biler på fabrikkens alder. Og siden vår fabrikk er ny (dvs. den er 0 år gammel), deler vi på 0, noe vi ikke kan gjøre i matematikk. Følgelig avsluttes programmet med en feil.

Hva burde vi ha gjort?

Legg all logikken i en egen metode. La oss kalle det printFactoryInfo() . Du kan sende et CarFactory -objekt til det som et argument. Du kan legge all logikken der, og samtidig håndtere potensielle feil (som vår som involverer null år). Hver sin smak. Konstruktører er nødvendig for å angi gyldig objekttilstand. Vi har metoder for forretningslogikk. Ikke bland det ene med det andre. For å forsterke det du lærte, foreslår vi at du ser en videoleksjon fra vårt Java-kurs
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION