Een gids voor constructeurs in Java

1. Inleiding

Constructeurs zijn de poortwachters van objectgeoriënteerd ontwerp.

In deze zelfstudie zullen we zien hoe ze fungeren als een enkele locatie van waaruit de interne status van het object dat wordt gemaakt, wordt geïnitialiseerd.

Laten we verder gaan en een eenvoudig object maken dat een bankrekening vertegenwoordigt.

2. Een bankrekening opzetten

Stel je voor dat we een klasse moeten maken die een bankrekening vertegenwoordigt. Het bevat een naam, aanmaakdatum en saldo.

Laten we ook het toString methode om de details naar de console af te drukken:

class BankAccount {String naam; LocalDateTime geopend; dubbele balans; @Override public String toString () {return String.format ("% s,% s,% f", this.name, this.opened.toString (), this.balance); }} 

Deze klasse bevat nu alle noodzakelijke velden die nodig zijn om informatie over een bankrekening op te slaan, maar bevat nog geen constructor.

Dit betekent dat als we een nieuw object maken, de veldwaarden niet worden geïnitialiseerd:

BankAccount-account = nieuwe BankAccount (); account.toString (); 

Het uitvoeren van het toString bovenstaande methode resulteert in een uitzondering omdat de objecten naam en geopend zijn nog steeds nul:

java.lang.NullPointerException op com.baeldung.constructors.BankAccount.toString (BankAccount.java:12) op com.baeldung.constructors.ConstructorUnitTest .givenNoExplicitContructor_whenUsed_thenFails (ConstructorUnitTest.java:23) 

3. Een constructeur zonder argumenten

Laten we dat oplossen met een constructor:

class BankAccount {openbare BankAccount () {this.name = ""; this.opened = LocalDateTime.now (); this.balance = 0.0d; }} 

Let op een paar dingen over de constructor die we zojuist hebben geschreven. Ten eerste is het een methode, maar het heeft geen retourtype. Dat komt omdat een constructor impliciet het type object retourneert dat het maakt. Roeping nieuwe BankAccount () zal nu de constructor hierboven aanroepen.

Ten tweede zijn er geen argumenten voor nodig. Dit specifieke type constructor wordt een n genoemdo-argument constructor.

Maar waarom hadden we het niet voor de eerste keer nodig? Het is omdat wanneer we schrijf niet expliciet een constructor, de compiler voegt een standaard constructor zonder argument toe.

Dit is de reden waarom we het object de eerste keer konden construeren, ook al hebben we niet expliciet een constructor geschreven. De standaard, geen argument constructor zal simpelweg alle leden op hun standaard waarden zetten.

Dat is voor objecten nul, wat resulteerde in de uitzondering die we eerder zagen.

4. Een geparametriseerde constructor

Een echt voordeel van constructeurs is nu dat ze ons helpen te onderhouden inkapseling bij het injecteren van staat in het object.

Dus om iets echt nuttigs met deze bankrekening te doen, moeten we in staat zijn om enkele beginwaarden in het object te injecteren.

Om dat te doen, laten we een geparametriseerde constructor, dat wil zeggen, een constructor die enkele argumenten nodig heeft:

class BankAccount {public BankAccount () {...} public BankAccount (String naam, LocalDateTime geopend, dubbel saldo) {this.name = naam; this.opened = geopend; this.balance = balans; }} 

Nu kunnen we iets nuttigs doen met onze Bankrekening klasse:

 LocalDateTime geopend = LocalDateTime.of (2018, maand.JUNE, 29, 06, 30, 00); BankAccount-account = nieuwe BankAccount ("Tom", geopend, 1000.0f); account.toString (); 

Merk op dat onze klasse nu 2 constructors heeft. Een expliciete constructor zonder argument en een constructor met parameters.

We kunnen zoveel constructors maken als we willen, maar we willen er waarschijnlijk niet teveel van maken. Dit zou een beetje verwarrend zijn.

Als we te veel constructors in onze code vinden, kunnen een paar Creational Design Patterns nuttig zijn.

5. Een kopieerconstructor

Constructeurs hoeven niet beperkt te zijn tot alleen initialisatie. Ze kunnen ook worden gebruikt om gedrag te creëren. Stel je voor dat we een nieuw account moeten kunnen aanmaken op basis van een bestaand account.

De nieuwe rekening moet dezelfde naam hebben als de oude rekening, de huidige aanmaakdatum en geen geld. We kunnen dat doen met een kopieer constructor:

openbare BankAccount (BankAccount andere) {this.name = other.name; this.opened = LocalDateTime.now (); this.balance = 0.0f; } 

Nu hebben we het volgende gedrag:

LocalDateTime geopend = LocalDateTime.of (2018, maand.JUNE, 29, 06, 30, 00); BankAccount account = nieuwe BankAccount ("Tim", geopend, 1000.0f); BankAccount newAccount = nieuwe BankAccount (rekening); assertThat (account.getName ()). isEqualTo (newAccount.getName ()); assertThat (account.getOpened ()). isNotEqualTo (newAccount.getOpened ()); assertThat (newAccount.getBalance ()). isEqualTo (0.0f); 

6. Een geketende constructeur

Natuurlijk kunnen we enkele van de constructorparameters of geef een aantal van hen standaardwaarden.

We kunnen bijvoorbeeld gewoon een nieuwe bankrekening maken met alleen de naam.

Laten we dus een constructor maken met een naam parameter en geef de andere parameters standaardwaarden:

openbare BankAccount (String naam, LocalDateTime geopend, dubbel saldo) {this.name = naam; this.opened = geopend; this.balance = balans; } openbare BankAccount (String naam) {this (name, LocalDateTime.now (), 0.0f); }

Met het trefwoord dit, we bellen de andere constructor.

Dat moeten we onthouden als we een constructor van een superklasse willen ketenen, moeten we super in plaats van dit.

Onthoud dat ook dit of super expressie moet altijd de eerste verklaring zijn.

7. Waardetypes

Een interessant gebruik van constructors in Java is het maken van Waardeobjecten. Een value-object is een object waarvan de interne toestand na initialisatie niet verandert.

Dat wil zeggen, het object is onveranderlijk. Onveranderlijkheid in Java is een beetje genuanceerd en je moet voorzichtig zijn bij het maken van objecten.

Laten we doorgaan en een onveranderlijke klasse maken:

klasse Transactie {laatste BankAccount bankAccount; laatste LocalDateTime-datum; laatste dubbel bedrag; openbare transactie (BankAccount-account, LocalDateTime-datum, dubbel bedrag) {this.bankAccount = account; this.date = datum; this.amount = bedrag; }} 

Merk op dat we nu de laatste trefwoord bij het definiëren van de leden van de klas. Dit betekent dat elk van deze leden alleen kan worden geïnitialiseerd binnen de constructor van de klasse. Ze kunnen later niet opnieuw worden toegewezen binnen een andere methode. We kunnen die waarden lezen, maar ze niet veranderen.

Als we meerdere constructors maken voor het Transactie class, moet elke constructor elke laatste variabele initialiseren. Als u dit niet doet, resulteert dit in een compilatiefout.

8. Conclusie

We hebben een rondleiding gekregen door de verschillende manieren waarop constructeurs objecten bouwen. Bij oordeelkundig gebruik vormen constructies de basisbouwstenen van Object-Oriented Design in Java.

Zoals altijd zijn codevoorbeelden te vinden op GitHub.