Uforanderlige objekter i Java

1. Oversigt

I denne vejledning lærer vi, hvad der gør et objekt uforanderligt, hvordan man opnår uforanderlighed i Java, og hvilke fordele der følger med at gøre det.

2. Hvad er et uforanderligt objekt?

Et uforanderligt objekt er et objekt, hvis indre tilstand forbliver konstant, efter at den er oprettet fuldstændigt.

Dette betyder, at den offentlige API for et uforanderligt objekt garanterer os, at det opfører sig på samme måde i hele dets levetid.

Hvis vi kigger på klassen Snor, kan vi se, at selv når dets API ser ud til at give os en ændret adfærd med dens erstatte metode, originalen Snor ændrer sig ikke:

String name = "baeldung"; String newName = name.replace ("dung", "----"); assertEquals ("baeldung", navn); assertEquals ("bael ----", newName);

API'en giver os skrivebeskyttede metoder, den bør aldrig omfatte metoder, der ændrer objektets interne tilstand.

3. Den endelig Nøgleord i Java

Før vi prøver at opnå uforanderlighed i Java, skal vi tale om endelig nøgleord.

I Java, variabler er som standard mutable, hvilket betyder, at vi kan ændre den værdi, de har.

Ved hjælp af endelig nøgleord, når deklarerer en variabel, vil Java-kompilatoren ikke lade os ændre værdien af ​​den variabel. I stedet rapporterer den en kompileringstidsfejl:

endelig strengnavn = "baeldung"; navn = "bael ...";

Noter det endelig kun forbyder os at ændre den reference, variablen indeholder, den beskytter os ikke mod at ændre den interne tilstand af det objekt, den henviser til, ved hjælp af dens offentlige API:

endelige listestrenge = ny ArrayList (); assertEquals (0, strings.size ()); strings.add ("baeldung"); assertEquals (0, strings.size ());

Sekundet hævderLige mislykkes, fordi tilføjelse af et element til listen ændrer størrelse, derfor er det ikke et uforanderligt objekt.

4. Uforanderlighed i Java

Nu hvor vi ved, hvordan vi kan undgå ændringer i indholdet af en variabel, kan vi bruge den til at opbygge API af uforanderlige objekter.

Opbygning af API af et uforanderligt objekt kræver, at vi garanterer, at dets interne tilstand ikke ændrer sig, uanset hvordan vi bruger dets API.

Et skridt fremad i den rigtige retning er at bruge endelig når man erklærer dets attributter:

klasse Penge {privat endelig dobbeltbeløb; privat endelig valuta // ...}

Bemærk, at Java garanterer os, at værdien af beløb ændres ikke, det er tilfældet med alle primitive typevariabler.

Men i vores eksempel er vi kun garanteret, at betalingsmiddel ændrer sig ikke, så vi må stole på betalingsmiddel API til at beskytte sig mod ændringer.

Det meste af tiden har vi brug for attributterne for et objekt til at holde brugerdefinerede værdier, og stedet for at initialisere den interne tilstand for et uforanderligt objekt er dets konstruktør:

klasse Penge {// ... offentlige penge (dobbeltbeløb, valuta) {this.amount = beløb; denne.valuta = valuta; } offentlig valuta getCurrency () {returvaluta; } offentlig dobbelt getAmount () {returbeløb; }}

Som vi har sagt før, for at imødekomme kravene i en uforanderlig API, er vores Penge klasse har kun skrivebeskyttede metoder.

Ved hjælp af refleksions-API kan vi bryde uforanderlighed og ændre uforanderlige objekter. Imidlertid er refleksion i strid med det uforanderlige objekts offentlige API, og normalt bør vi undgå at gøre dette.

5. Fordele

Da den indre tilstand af et uforanderligt objekt forbliver konstant i tiden, vi kan dele det sikkert mellem flere tråde.

Vi kan også bruge det frit, og ingen af ​​objekterne, der refererer til det, bemærker nogen forskel, det kan vi sige uforanderlige genstande er fri for bivirkninger.

6. Konklusion

Uforanderlige genstande ændrer ikke deres interne tilstand i tide, de er trådsikre og uden bivirkninger. På grund af disse egenskaber er uforanderlige objekter også særligt nyttige, når det drejer sig om multitrådsmiljøer.

Du kan finde eksemplerne i denne artikel over på GitHub.