Hoi! Vandaag zullen we een heel belangrijk onderwerp bespreken dat betrekking heeft op onze objecten. Zonder overdrijving kunnen we zeggen dat je dit onderwerp elke dag in het echte leven zult gebruiken! We hebben het over Java Constructors. Dit is misschien de eerste keer dat je deze term hoort, maar je hebt eigenlijk al constructors gebruikt. Je besefte het gewoon niet :) Daar overtuigen we ons later van.
Weet je nog dat we aan het begin van de les zeiden dat je al constructors hebt gebruikt zonder het te beseffen? We meenden wat we zeiden. Feit is dat elke klasse in Java een zogenaamde standaardconstructor heeft. Er zijn geen argumenten voor nodig, maar het wordt elke keer aangeroepen wanneer u een object van een willekeurige klasse maakt.
(CarFactory.java:15) bij CarFactory.main(CarFactory.java:23) Proces voltooid met afsluitcode 1
Boom! Het programma eindigt met een soort onbegrijpelijke fout. Kun je proberen de oorzaak te raden? Het probleem zit hem in de logica die we in de constructor stoppen. Meer specifiek, deze regel:
Wat zijn constructeurs in vredesnaam en waarom zijn ze nodig?
Laten we twee voorbeelden bekijken.
public class Car {
String model;
int maxSpeed;
public static void main(String[] args) {
Car bugatti = new Car();
bugatti.model = "Bugatti Veyron";
bugatti.maxSpeed = 378;
}
}
We hebben onze auto gemaakt en het model en de maximale snelheid bepaald. Maar het Car- object zou natuurlijk geen 2 velden hebben in een echt project. Het kan bijvoorbeeld 16 velden hebben!
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";
}
}
We hebben een nieuw auto- object gemaakt. Er is één probleem: we hebben 16 velden, maar we hebben er slechts 12 geïnitialiseerd ! Bekijk nu de code en probeer de velden te vinden die we vergeten zijn! Niet zo makkelijk, hè? In deze situatie kan een programmeur gemakkelijk een fout maken en een veld niet initialiseren. Als gevolg hiervan zal het programma zich niet correct gedragen:
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);
}
}
Console-uitgang: Model: Bugatti Veyron. Motorvolume: 6.3. Kofferbakvolume: 0. Cabinemateriaal: nul. Wielbreedte: 0. Gekocht in 2018 door Mr. null Uw koper, die $ 2 miljoen voor de auto heeft gegeven, zal er duidelijk niet van houden om " Mr. null " genoemd te worden! Maar serieus, het komt erop neer dat ons programma een object verkeerd heeft gemaakt: een auto met een wielbreedte van 0 (dwz helemaal geen wielen), een ontbrekende kofferbak, een cabine gemaakt van een onbekend materiaal en vooral een ongedefinieerde eigenaar . Je kunt je alleen maar voorstellen hoe zo'n fout kan "afgaan" wanneer het programma wordt uitgevoerd! We moeten dergelijke situaties op de een of andere manier vermijden. We moeten ons programma beperken: bij het maken van een nieuwe autoobject, willen we dat de velden, zoals het model en de maximale snelheid, altijd worden gespecificeerd. Anders willen we voorkomen dat het object wordt gemaakt. Constructeurs kunnen deze taak met gemak aan. Ze hebben hun naam niet voor niets gekregen. De constructor maakt een soort "skelet" van de klasse waaraan elk nieuw object moet voldoen. Laten we voor het gemak teruggaan naar de eenvoudigere versie van de klasse Auto met twee velden. Rekening houdend met onze vereisten, ziet de constructor van de autoklasse er als volgt uit:
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);
}
Merk op hoe een constructor wordt gedeclareerd. Het is vergelijkbaar met een gewone methode, maar het heeft geen retourtype. Bovendien specificeert de constructor de klassenaam ( Car ) beginnend met een hoofdletter. Bovendien wordt de constructor gebruikt met een trefwoord dat nieuw voor u is: this . Het sleutelwoord this is om een bepaald object aan te duiden. De code in de constructor
public Car(String model, int maxSpeed) {
this.model = model;
this.maxSpeed = maxSpeed;
}
kan bijna woordelijk worden geïnterpreteerd: "Het model voor deze auto (degene die we nu maken) is het modelargument dat aan de constructeur wordt doorgegeven. De maxSpeed voor deze auto (degene die we maken) is het maxSpeed- argument dat wordt doorgegeven aan de constructeur." En dat is precies wat er gebeurt:
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);
}
}
Console-uitvoer: Bugatti Veyron 378 De constructeur heeft de vereiste waarden correct toegewezen. Het is je misschien opgevallen dat een constructor erg lijkt op een gewone methode! Zo is het. Een constructor is eigenlijk een methode, maar met specifieke kenmerken :) Net als bij methoden hebben we argumenten doorgegeven aan onze constructor. En net zoals het aanroepen van een methode, werkt het aanroepen van een constructor alleen als u deze opgeeft:
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!
}
}
Je kunt zien dat de constructor bereikt wat we probeerden te bereiken. Nu kun je geen auto maken zonder snelheid of model! De overeenkomst tussen constructors en methoden houdt hier niet op. Net als methoden kunnen constructors overbelast raken. Stel je voor dat je thuis 2 katten hebt. Je hebt er een als kitten gekregen. Maar de tweede heb je van de straat gehaald toen hij al volgroeid was, en je weet niet precies hoe oud hij is. In dit geval willen we dat ons programma twee soorten katten kan maken: katten met een naam en leeftijd (voor de eerste kat) en katten met alleen een naam (voor de tweede kat). Hiervoor zullen we de constructor overbelasten:
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");
}
}
Naast de originele constructor met de parameters "name" en "age", hebben we er nog een toegevoegd met alleen een parameter name. Op precies dezelfde manier waarop we in vorige lessen methodes hebben overbelast. Nu kunnen we beide soorten katten maken :)
![Waarom hebben we constructeurs nodig? - 2](https://cdn.codegym.cc/images/article/66a3ff7c-563d-4f53-af6e-3a03f1cf8ace/512.jpeg)
public class Cat {
public static void main(String[] args) {
Cat smudge = new Cat(); // The default constructor is invoked here
}
}
Op het eerste gezicht is het onzichtbaar. We hebben een object gemaakt, dus wat? Waar doet de constructeur hier iets? Om het te zien, schrijven we expliciet een lege constructor voor de klasse Cat . We zullen er een zin in weergeven. Als de zin wordt weergegeven, is de constructor aangeroepen.
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
}
}
Console-uitvoer: er is een kat gemaakt! Daar is de bevestiging! De standaard constructor is altijd onzichtbaar aanwezig in je klassen. Maar je moet er nog één ding over weten. De standaardconstructor wordt uit een klasse geëlimineerd zodra u een constructor met argumenten maakt. In feite hebben we hierboven al het bewijs hiervan gezien. Het stond in deze 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 smudge = new Cat(); //Error!
}
}
We konden geen Cat maken zonder naam en leeftijd, omdat we een Cat- constructor met string- en int- parameters hebben gedeclareerd. Hierdoor verdween de standaardconstructor onmiddellijk uit de klasse. Onthoud dus dat als u meerdere constructors in uw klasse nodig heeft, inclusief een constructor zonder argumenten, u deze afzonderlijk moet declareren. Stel dat we een programma maken voor een dierenkliniek. Onze kliniek wil goede daden verrichten en dakloze kittens helpen waarvan de naam en leeftijd onbekend zijn. Dan zou onze code er zo uit moeten zien:
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 we een expliciete standaardconstructor hebben geschreven, kunnen we beide typen katten maken :) Zoals bij elke methode is de volgorde van argumenten die aan een constructor worden doorgegeven erg belangrijk. Laten we de argumenten voor naam en leeftijd in onze constructor omwisselen.
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!
}
}
Een fout! De constructor geeft duidelijk aan dat wanneer een Cat- object wordt gemaakt, het een nummer en een tekenreeks moet worden doorgegeven, in deze volgorde. Onze code werkt dus niet. Onthoud dit en houd er rekening mee bij het declareren van uw eigen klassen:
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
Dit zijn twee totaal verschillende constructeurs! Als we het antwoord op de vraag "Waarom heb ik een constructor nodig?" in één enkele zin zouden uitdrukken, zouden we kunnen zeggen: "Om ervoor te zorgen dat objecten altijd een geldige status hebben". Wanneer u constructors gebruikt, worden al uw variabelen correct geïnitialiseerd. Uw programma's zullen geen auto's hebben met een snelheid van 0 of andere "ongeldige" objecten. Hun belangrijkste voordeel is voor de programmeur. Als u velden handmatig initialiseert (na het maken van een object), is het risico groot dat u iets over het hoofd ziet en een bug introduceert. Maar dit gebeurt niet met een constructor: als u niet alle vereiste argumenten doorgeeft of als u de verkeerde soorten argumenten doorgeeft, registreert de compiler onmiddellijk een fout. We moeten ook apart zeggen dat je je programma niet moet zetten' s logica binnen een constructor. Dit is waar methoden voor zijn. Methoden zijn waar u alle vereiste functionaliteit moet definiëren. Laten we eens kijken waarom het toevoegen van logica aan een constructor een slecht idee is:
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);
}
}
We hebben een CarFactory- klasse die de autofabriek beschrijft. Binnen de constructor initialiseren we alle velden en voegen we wat logica toe: we tonen wat informatie over de fabriek. Het lijkt erop dat hier niets ergs aan is. Het programma werkt prima. Console-output: Onze autofabriek heet Ford. Het werd 115 jaar geleden opgericht. Sindsdien heeft het 5.000.000 auto's geproduceerd. Gemiddeld produceert het 434.782 auto's per jaar. Maar we hebben eigenlijk een vertraagde mijn gelegd. En dit soort code kan heel gemakkelijk tot fouten leiden. Stel dat we het nu niet over Ford hebben, maar over een nieuwe fabriek genaamd "Amigo Motors", die nog geen jaar bestaat en 1000 auto's heeft geproduceerd:
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);
}
}
Console output: Onze autofabriek heet Amigo Motors Exception in thread "main" java.lang.ArithmeticException: / by zero Het werd 0 jaar geleden opgericht Sindsdien heeft het 1000 auto's geproduceerd bij CarFactory.
System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Hier voer je een berekening uit en deel je het aantal geproduceerde auto's door de leeftijd van de fabriek. En aangezien onze fabriek nieuw is (dwz 0 jaar oud), delen we door 0, wat we niet kunnen doen met wiskunde. Bijgevolg eindigt het programma met een fout.
GO TO FULL VERSION