En guide til konstruktører i Java

1. Introduksjon

Konstruktører er portvaktene til objektorientert design.

I denne opplæringen ser vi hvordan de fungerer som et enkelt sted å initialisere den interne tilstanden til objektet som blir opprettet.

La oss gå videre og lage et enkelt objekt som representerer en bankkonto.

2. Opprette en bankkonto

Tenk deg at vi trenger å lage en klasse som representerer en bankkonto. Den inneholder navn, opprettelsesdato og balanse.

La oss også overstyre toString metode for å skrive ut detaljene til konsollen:

klasse BankAccount {Strengnavn; LocalDateTime åpnet; dobbel balanse; @Override public String toString () {return String.format ("% s,% s,% f", this.name, this.opened.toString (), this.balance); }} 

Nå inneholder denne klassen alle nødvendige felt som kreves for å lagre informasjon om en bankkonto, men den inneholder ikke en konstruktør ennå.

Dette betyr at hvis vi oppretter et nytt objekt, vil ikke feltverdiene initialiseres:

BankAccount-konto = ny BankAccount (); account.toString (); 

Kjører toString metoden ovenfor vil resultere i et unntak fordi objektene Navn og åpnet er fortsatt null:

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

3. En uten argumentkonstruktør

La oss fikse det med en konstruktør:

klasse BankAccount {public BankAccount () {this.name = ""; this.opened = LocalDateTime.now (); dette. balanse = 0,0d; }} 

Legg merke til noen få ting om konstruktøren som vi nettopp skrev. For det første er det en metode, men den har ingen returtype. Det er fordi en konstruktør implisitt returnerer typen objekt som den lager. Ringer ny BankAccount () nå vil ringe konstruktøren ovenfor.

For det andre tar det ingen argumenter. Denne spesielle typen konstruktør kalles en no-argumentkonstruktør.

Hvorfor trengte vi det ikke for første gang? Det er fordi når vi ikke eksplisitt skriv noen konstruktører, kompilatoren legger til en standard konstruktør uten argument.

Dette var grunnen til at vi klarte å konstruere objektet første gang, selv om vi ikke skrev en konstruktør eksplisitt. Standard, ingen argumentkonstruktør vil ganske enkelt sette alle medlemmene til standardverdiene.

For gjenstander, det er det null, som resulterte i unntaket som vi så tidligere.

4. En parameterisert konstruktør

Nå er en reell fordel med konstruktører at de hjelper oss med å opprettholde innkapsling når du injiserer tilstand i objektet.

Så for å gjøre noe veldig nyttig med denne bankkontoen, må vi være i stand til å faktisk injisere noen innledende verdier i objektet.

Å gjøre det, la oss skrive en parametriserte konstruktør, det vil si en konstruktør som tar noen argumenter:

class BankAccount {public BankAccount () {...} public BankAccount (Strengnavn, LocalDateTime åpnet, dobbel saldo) {this.name = name; dette. åpnet = åpnet; denne. balanse = balanse; }} 

Nå kan vi gjøre noe nyttig med vårt Bankkonto klasse:

 LocalDateTime åpnet = LocalDateTime.of (2018, måned. JUNI, 29, 06, 30, 00); BankAccount-konto = ny BankAccount ("Tom", åpnet, 1000.0f); account.toString (); 

Legg merke til at klassen vår nå har to konstruktører. En eksplisitt, ingen argumentkonstruktør og en parameterisert konstruktør.

Vi kan lage så mange konstruktører som vi vil, men vi vil sannsynligvis ikke lage for mange. Dette ville være litt forvirrende.

Hvis vi finner for mange konstruktører i koden vår, kan noen få Creational Design Patterns være nyttige.

5. En kopikonstruktør

Konstruktører trenger ikke være begrenset til initialisering alene. De kan også brukes til å skape atferd. Tenk deg at vi trenger å kunne opprette en ny konto fra en eksisterende konto.

Den nye kontoen skal ha samme navn som den gamle kontoen, dagens opprettelsesdato og ingen midler. Vi kan gjøre det ved hjelp av en kopikonstruktør:

offentlig BankAccount (annen BankAccount) {this.name = other.name; this.opened = LocalDateTime.now (); denne.balanse = 0,0f; } 

Nå har vi følgende oppførsel:

LocalDateTime åpnet = LocalDateTime.of (2018, måned. JUNI, 29, 06, 30, 00); BankAccount-konto = ny BankAccount ("Tim", åpnet, 1000.0f); BankAccount newAccount = ny BankAccount (konto); assertThat (account.getName ()). isEqualTo (newAccount.getName ()); assertThat (account.getOpened ()). erNotEqualTo (newAccount.getOpened ()); assertThat (newAccount.getBalance ()). isEqualTo (0.0f); 

6. En lenket konstruktør

Selvfølgelig kan vi være i stand til å utlede noen av konstruktorparametrene eller gi noen av dem standardverdier.

For eksempel kan vi bare opprette en ny bankkonto med bare navnet.

Så la oss lage en konstruktør med en Navn parameter og gi de andre parameterne standardverdier:

offentlig BankAccount (strengnavn, LocalDateTime åpnet, dobbel saldo) {this.name = navn; dette. åpnet = åpnet; denne. balanse = balanse; } offentlig BankAccount (strengnavn) {this (name, LocalDateTime.now (), 0.0f); }

Med nøkkelordet dette, vi ringer til den andre konstruktøren.

Vi må huske det hvis vi vil kjede en superklassekonstruktør, må vi bruke super i stedet for dette.

Husk det også dette eller super uttrykk bør alltid være den første utsagnet.

7. Verdityper

En interessant bruk av konstruktører i Java er i etableringen av Verdiobjekter. Et verdiobjekt er et objekt som ikke endrer sin interne tilstand etter initialisering.

Det vil si at objektet er uforanderlig. Uforanderlighet i Java er litt nyansert, og det bør utvises forsiktighet når du lager objekter.

La oss gå videre og lage en uforanderlig klasse:

klasse Transaksjon {endelig BankAccount bankAccount; endelig LocalDateTime-dato; endelig dobbeltbeløp; offentlig transaksjon (BankAccount-konto, LocalDateTime-dato, dobbelt beløp) {this.bankAccount = konto; denne datoen = dato; dette.beløp = beløp; }} 

Legg merke til at vi nå bruker endelig nøkkelord når du definerer medlemmene i klassen. Dette betyr at hvert av disse medlemmene bare kan initialiseres i konstruktøren av klassen. De kan ikke tildeles senere senere i noen annen metode. Vi kan lese disse verdiene, men ikke endre dem.

Hvis vi lager flere konstruktører for Transaksjon klasse, vil hver konstruktør måtte initialisere hver endelige variabel. Hvis du ikke gjør det, vil det føre til en kompileringsfeil.

8. Konklusjon

Vi har tatt en tur gjennom de forskjellige måtene konstruktører bygger gjenstander på. Når konstruksjonene brukes på en hensiktsmessig måte, danner de de grunnleggende byggesteinene for objektorientert design i Java.

Som alltid kan kodeeksempler bli funnet på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found