Vedhæftning af værdier til Java Enum

1. Introduktion

Java enum type giver en sprogstøttet måde at oprette og bruge konstante værdier på. Ved at definere et endeligt sæt værdier, enum er mere typesikker end konstante bogstavelige variabler som Snor eller int.

Imidlertid, enum værdier kræves for at være gyldige identifikatorer, og vi opfordres til at bruge SCREAMING_SNAKE_CASE efter konvention.

I betragtning af disse begrænsninger, det enum værdi alene er ikke egnet til strenge, der kan læses af mennesker eller værdier, der ikke er streng.

I denne vejledning bruger vi enum'S funktioner som en Java-klasse til at vedhæfte de værdier, vi ønsker.

2. Brug af Java Enum som en klasse

Vi opretter ofte en enum som en simpel liste over værdier. For eksempel er her de første to rækker i det periodiske system som en simpel enum:

public enum Element {H, HE, LI, BE, B, C, N, O, F, NE}

Ved hjælp af syntaksen ovenfor har vi oprettet ti statiske, endelige forekomster af enum som hedder Element. Selvom dette er meget effektivt, har vi kun fanget element-symbolerne. Og mens store bogstaver er passende for Java-konstanter, er det ikke sådan, vi normalt skriver symbolerne.

Desuden mangler vi også andre egenskaber ved elementerne i det periodiske system, som navnet og atomvægten.

Selvom enum type har særlig opførsel i Java, kan vi tilføje konstruktører, felter og metoder som vi gør med andre klasser. På grund af dette kan vi forbedre vores enum at inkludere de værdier, vi har brug for.

3. Tilføjelse af en konstruktør og et sidste felt

Lad os starte med at tilføje elementnavne. Vi sætter navnene til a endelig variabel ved hjælp af en konstruktør:

offentlig enum Element {H ("Hydrogen"), HE ("Helium"), // ... NE ("Neon"); offentlig endelig String label; private Element (strengetiket) {this.label = label; }}

Først og fremmest bemærker vi den specielle syntaks i erklæringslisten. Sådan påberåbes en konstruktør enum typer. Selvom det er ulovligt at bruge ny operatør til en enum, kan vi videregive konstruktørargumenter i erklæringslisten.

Vi erklærer derefter en instansvariabel etiket. Der er et par ting at bemærke om det.

For det første valgte vi etiket identifikator i stedet for navn. Selvom medlemsfeltet navn er tilgængelig til brug, lad os vælge etiket for at undgå forveksling med det foruddefinerede Enum.name () metode.

For det andet vores etiket felt er endelig. Mens felter i en enum behøver ikke at være endelig, i de fleste tilfælde ønsker vi ikke, at vores etiketter skal ændres. I ånden af enum værdier er konstante, det giver mening.

Endelig blev etiket felt er offentligt. Derfor kan vi få adgang til etiketten direkte:

System.out.println (BE.label);

På den anden side kan feltet være privat, åbnes med en getLabel () metode. Med henblik på kortfattethed fortsætter denne artikel med at bruge den offentlige feltstil.

4. Find Java Enum Værdier

Java giver en valueOf (String) metode til alle enum typer. Således kan vi altid få en enum værdi baseret på det deklarerede navn:

assertSame (Element.LI, Element.valueOf ("LI"));

Vi ønsker dog måske at slå op enum værdi ved vores etiketfelt også. For at gøre det kan vi tilføje en statisk metode:

offentlig statisk Element valueOfLabel (strengetiket) {for (Element e: værdier ()) {hvis (e.label.equals (label)) {return e; }} returner null; }

Det statiske valueOfLabel () metode gentager Element værdier, indtil den finder et match. Det vender tilbage nul hvis der ikke findes nogen match. Omvendt kunne en undtagelse kastes i stedet for at vende tilbage nul.

Lad os se et hurtigt eksempel ved hjælp af vores valueOfLabel () metode:

assertSame (Element.LI, Element.valueOfLabel ("Lithium"));

5. Caching af opslagsværdier

Vi kan undgå at gentage enum værdier ved hjælp af a Kort at cache etiketterne. For at gøre dette definerer vi en statisk endelig kort og udfyld det, når klassen indlæses:

offentlig enum Element {// ... enum værdier privat statisk endelig Kort BY_LABEL = ny HashMap (); statisk {for (Element e: værdier ()) {BY_LABEL.put (e.label, e); }} // ... felter, konstruktør, metoder offentlig statisk Element værdiOfLabel (strengetiket) {return BY_LABEL.get (label); }}

Som et resultat af cachelagring, blev enum værdier gentages kun en gang, og valueOfLabel () metoden er forenklet.

Som et alternativ kan vi dovent konstruere cachen, når den først åbnes i valueOfLabel () metode. I så fald skal kortadgang synkroniseres for at forhindre samtidighedsproblemer.

6. Vedhæftning af flere værdier

Det Enum konstruktør kan acceptere flere værdier. For at illustrere, lad os tilføje atomnummeret som et int og atomvægten som en flyde:

offentligt enum Element {H ("Hydrogen", 1, 1.008f), HE ("Helium", 2, 4.0026f), // ... NE ("Neon", 10, 20.180f); privat statisk endelig kort BY_LABEL = ny HashMap (); privat statisk endelig kort BY_ATOMIC_NUMBER = nyt HashMap (); privat statisk endelig kort BY_ATOMIC_WEIGHT = ny HashMap (); statisk {for (Element e: værdier ()) {BY_LABEL.put (e.label, e); BY_ATOMIC_NUMBER.put (e.atomicNumber, e); BY_ATOMIC_WEIGHT.put (e.atomicWeight, e); }} offentlig endelig strengetiket; offentlig endelig int atomicNumber; offentlig endelig flydende atomvægt; private Element (String label, int atomicNumber, float atomicWeight) {this.label = label; this.atomicNumber = atomicNumber; this.atomicWeight = atomicWeight; } offentlig statisk elementværdiOfLabel (strengetiket) {return BY_LABEL.get (label); } public static Element valueOfAtomicNumber (int number) {return BY_ATOMIC_NUMBER.get (number); } offentlig statisk elementværdiOfAtomicWeight (float weight) {return BY_ATOMIC_WEIGHT.get (weight); }}

På samme måde kan vi tilføje de værdier, vi ønsker, til enum, f.eks. de korrekte sagsymboler, "Han", "Li" og "Vær".

Desuden kan vi tilføje beregnede værdier til vores enum ved at tilføje metoder til at udføre operationer.

7. Styring af grænsefladen

Som et resultat af tilføjelse af felter og metoder til vores enum, vi har ændret sin offentlige grænseflade. Derfor er vores kode, der bruger kernen Enumnavn() og Værdi af() metoder, vil være uvidende om vores nye felter.

Det statiskVærdi af() metoden er allerede defineret for os af Java-sproget. Derfor kan vi ikke give vores egne Værdi af() implementering.

Tilsvarende fordi Enum.name () metode er endelig, vi kan heller ikke tilsidesætte det.

Som et resultat er der ingen praktisk måde at udnytte vores ekstra felter ved hjælp af standarden Enum API. Lad os i stedet se på nogle forskellige måder at eksponere vores felter på.

7.1. Tilsidesættelse toString ()

Tilsidesættelse toString () kan være et alternativ til at tilsidesætte navn():

@ Override public String toString () {return this.label; }

Som standard, Enum.toString () returnerer den samme værdi som Enum.navn ().

7.2. Implementering af et interface

Det enum type Java kan implementere grænseflader. Mens denne tilgang ikke er så generisk som Enum API, grænseflader hjælper os med at generalisere.

Lad os overveje denne grænseflade:

offentlig grænseflade mærket {String label (); }

For sammenhæng med Enum.name () metode, vores etiket() metoden har ikke en præfiks.

Og fordi den valueOfLabel () metode er statisk, vi inkluderer det ikke i vores grænseflade.

Endelig kan vi implementere grænsefladen i vores enum:

public enum Element implementerer mærket {// ... @ Override public String label () {return label; } // ...}

En fordel ved denne tilgang er, at Mærket interface kan anvendes til enhver klasse, ikke kun enum typer. I stedet for at stole på det generiske Enum API, vi har nu en mere kontekstspecifik API.

8. Konklusion

I denne artikel har vi udforsket mange funktioner i Java Enum implementering. Ved at tilføje konstruktører, felter og metoder ser vi, at enum kan gøre meget mere end bogstavelige konstanter.

Som altid kan den fulde kildekode til denne artikel findes på GitHub.