CodeGym/Java blog/Tilfældig/Java konstruktører
John Squirrels
Niveau
San Francisco

Java konstruktører

Udgivet i gruppen
Hej! I dag vil vi overveje et meget vigtigt emne, der vedrører vores objekter. Uden at overdrive kan vi sige, at du vil bruge dette emne i det virkelige liv hver dag! Vi taler om Java Constructors. Det kan være første gang, du hører dette udtryk, men du har faktisk allerede brugt konstruktører. Du var bare ikke klar over det :) Det overbeviser vi os selv om senere.

Hvad i alverden er konstruktører, og hvorfor er der brug for dem?

Lad os overveje 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 skabte vores bil og indstillede dens model og maksimale hastighed. Men bilobjektet ville åbenbart ikke have 2 felter i et rigtigt projekt. For eksempel kan den have 16 felter!
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 oprettet et nyt bilobjekt . Der er et problem: vi har 16 felter, men vi initialiserede kun 12 ! Se på koden nu og prøv at finde de felter, vi har glemt! Ikke så nemt, hva? I denne situation kan en programmør nemt lave en fejl og undlade at initialisere et eller andet felt. Som et resultat vil programmet opføre sig forkert:
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);

   }

}
Konsoludgang: Model: Bugatti Veyron. Motorvolumen: 6,3. Bagagerumsvolumen: 0. Kabinemateriale: null. Hjulbredde: 0. Købt i 2018 af Mr. null Din køber, der gav afkald på 2 millioner dollars for bilen, vil åbenbart ikke lide at blive kaldt " Mr. null "! Men seriøst, bundlinjen er, at vores program oprettede et objekt forkert: en bil med en hjulbredde på 0 (dvs. ingen hjul overhovedet), en manglende bagagerum, en kabine lavet af et ukendt materiale og frem for alt en udefineret ejer . Du kan kun forestille dig, hvordan sådan en fejl kan "gå ud", når programmet kører! Vi skal på en eller anden måde undgå sådanne situationer. Vi er nødt til at begrænse vores program: når vi opretter en ny bilobjekt, ønsker vi, at felterne, såsom model og maksimal hastighed, altid skal angives. Ellers ønsker vi at forhindre oprettelsen af ​​objektet. Konstruktører håndterer denne opgave med lethed. De fik deres navn af en grund. Konstruktøren opretter en slags klasse "skelet", som hvert nyt objekt skal matche. For nemheds skyld, lad os gå tilbage til den enklere version af bilklassen med to felter. I betragtning af vores krav vil bilklassens konstruktør se således ud:
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);
}
Bemærk, hvordan en konstruktør erklæres. Det ligner en almindelig metode, men den har ikke en returtype. Desuden specificerer konstruktøren klassenavnet ( Car ) begyndende med et stort bogstav. Derudover bruges konstruktøren med et nøgleord, der er nyt for dig: dette . Nøgleordet dette er for at angive et bestemt objekt. Koden i konstruktøren
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
kan fortolkes næsten ordret: "Modellen for denne bil (den vi laver nu) er modelargumentet, der er videregivet til konstruktøren. MaxSpeed ​​for denne bil (den vi opretter) er maxSpeed- argumentet, der sendes til konstruktør." Og det er bare hvad der sker:
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);
   }

}
Konsoludgang: Bugatti Veyron 378 Konstruktøren tildelte de påkrævede værdier korrekt. Du har måske bemærket, at en konstruktør minder meget om en almindelig metode! Sådan er det. En konstruktør er virkelig en metode, men med specifikke funktioner :) Ligesom med metoder, videregav vi argumenter til vores konstruktør. Og ligesom at kalde en metode, vil det ikke fungere at kalde en konstruktør, medmindre du angiver 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 opnår det, vi forsøgte at opnå. Nu kan du ikke skabe en bil uden en hastighed eller model! Ligheden mellem konstruktører og metoder slutter ikke her. Ligesom metoder kan konstruktører overbelastes. Forestil dig, at du har 2 katte derhjemme. Du fik en af ​​dem som killing. Men den anden tog du ind fra gaden, da den allerede var vokset, og du ved ikke præcis, hvor gammel den er. I dette tilfælde ønsker vi, at vores program skal være i stand til at skabe to slags katte: dem med navn og alder (for den første kat), og dem med kun et navn (til den anden kat). Til 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");
   }

}
Ud over den originale konstruktør med "navn" og "alder" parametre, tilføjede vi en mere med kun en navn parameter. Præcis på samme måde, som vi overbelastede metoder i tidligere lektioner. Nu kan vi skabe begge slags katte :)
Hvorfor har vi brug for konstruktører?  - 2
Husk, at vi i begyndelsen af ​​lektionen sagde, at du allerede har brugt konstruktører uden at være klar over det? Vi mente, hvad vi sagde. Faktum er, at hver klasse i Java har det, der kaldes en standardkonstruktør. Det kræver ingen argumenter, men det kaldes hver gang du opretter et objekt af en klasse.
public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Ved første øjekast er det usynligt. Vi skabte et objekt, hvad så? Hvor laver konstruktøren noget her? For at se det, lad os udtrykkeligt skrive en tom konstruktør til Cat- klassen. Vi viser en sætning inde i den. Hvis sætningen vises, blev konstruktøren påkaldt.
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
   }
}
Konsoludgang: En kat er blevet oprettet! Der er bekræftelsen! Standardkonstruktøren er altid usynligt til stede i dine klasser. Men du skal vide en ting mere om det. Standardkonstruktøren fjernes fra en klasse, når du opretter en konstruktør med argumenter. Faktisk har vi allerede set bevis for dette ovenfor. Det stod i denne kode:
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 oprette en kat uden navn og alder, fordi vi erklærede en Cat- konstruktør med streng- og int- parametre. Dette fik standardkonstruktøren til straks at forsvinde fra klassen. Så husk, at hvis du har brug for flere konstruktører i din klasse, inklusive en konstruktør uden argumenter, skal du angive det separat. Antag for eksempel, at vi laver et program for en veterinærklinik. Vores klinik ønsker at gøre gode gerninger og hjælpe hjemløse killinger, hvis navne og alder er ukendte. Så skulle vores kode se sådan ud:
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();
   }
}
Nu hvor vi har skrevet en eksplicit standardkonstruktør, kan vi oprette begge typer katte :) Som med enhver metode er rækkefølgen af ​​argumenter, der sendes til en konstruktør, meget vigtig. Lad os bytte navn og aldersargumenter i vores konstruktø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 fejl! Konstruktøren angiver klart, at når et Cat- objekt oprettes, skal det sendes et tal og en streng i denne rækkefølge. Så vores kode virker ikke. Husk at huske dette, og husk det, når du angiver 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;
}
Det er to helt forskellige konstruktører! Hvis vi i en enkelt sætning skulle udtrykke svaret på spørgsmålet "Hvorfor har jeg brug for en konstruktør?", kan vi sige: "For at sikre, at objekter altid har en gyldig tilstand". Når du bruger konstruktører, vil alle dine variable blive initialiseret korrekt. Dine programmer vil ikke have nogen biler med en hastighed på 0 eller andre "ugyldige" objekter. Deres største fordel er for programmøren. Hvis du initialiserer felter manuelt (efter at have oprettet et objekt), er der stor risiko for, at du går glip af noget og introducerer en fejl. Men dette vil ikke ske med en konstruktør: Hvis du ikke klarer alle de nødvendige argumenter, eller du sender de forkerte typer argumenter, vil compileren straks registrere en fejl. Vi må også separat sige, at du ikke skal lægge dit program' s logik inde i en konstruktør. Det er det, metoder er til. Metoder er, hvor du skal definere al den nødvendige funktionalitet. Lad os se, hvorfor det er en dårlig idé at tilføje logik til 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, der beskriver bilfabrikken. Inde i konstruktøren initialiserer vi alle felterne og inkluderer noget logik: vi viser nogle oplysninger om fabrikken. Det ser ud til, at der ikke er noget dårligt ved det her. Programmet fungerer fint. Konsolproduktion: Vores bilfabrik hedder Ford. Den blev grundlagt for 115 år siden. Siden dengang har den produceret 50000000 biler I gennemsnit producerer den 434782 biler om året. Men vi har faktisk lagt en tidsforsinket mine. Og denne slags kode kan meget nemt føre til fejl. Antag, at vi nu ikke taler om Ford, men om en ny fabrik kaldet "Amigo Motors", som har eksisteret i mindre end et år og har produceret 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);
   }
}
Konsol output: Vores bilfabrik hedder Amigo Motors Undtagelse i tråd "main" java.lang.ArithmeticException: / ved nul Den blev grundlagt for 0 år siden Siden dengang har den produceret 1000 biler på CarFactory. (CarFactory.java:15) på CarFactory.main(CarFactory.java:23) Processen afsluttet med udgangskode 1 Bom! Programmet ender med en form for uforståelig fejl. Kan du prøve at gætte årsagen? Problemet ligger i den logik, vi lægger i konstruktøren. Mere specifikt denne linje:
System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Her laver du en beregning og dividerer antallet af producerede biler med fabrikkens alder. Og da vores fabrik er ny (dvs. den er 0 år gammel), dividerer vi med 0, hvilket vi ikke kan i matematik. Følgelig afsluttes programmet med en fejl.

Hvad skulle vi have gjort?

Læg al logikken i en separat metode. Lad os kalde det printFactoryInfo() . Du kan sende et CarFactory -objekt til det som et argument. Du kan lægge al logikken der, og samtidig håndtere potentielle fejl (som vores, der involverer nul år). Til hver sit. Konstruktører er nødvendige for at indstille gyldig objekttilstand. Vi har metoder til forretningslogik. Bland ikke det ene med det andet. For at styrke det, du har lært, foreslår vi, at du ser en videolektion fra vores Java-kursus
Kommentarer
  • Populær
  • Ny
  • Gammel
Du skal være logget ind for at skrive en kommentar
Denne side har ingen kommentarer endnu