Programiranje

Kako uporabljati naštevane tipe v Javi

Koda Java, ki uporablja tradicionalne oštevilčene vrste, je problematična. Java 5 nam je dala boljšo alternativo v obliki tipov varnih naštevanj. V tem članku vam predstavim naštete tipe in tipe varnih naštevanj, pokažem vam, kako razglasite varno število in ga uporabite v stavku preklopa ter razpravljate o prilagajanju naštevanja tipov z dodajanjem podatkov in vedenj. Članek zaključim z raziskovanjem java.lang.Enum razred.

prenos Prenesite kodo Prenesite izvorno kodo za primere v tej vadnici Java 101. Ustvaril Jeff Friesen za JavaWorld /.

Od naštetih vrst do tipiziranih naštevanj

An našteti tip kot svoje vrednosti določi nabor sorodnih konstant. Primeri vključujejo tedenske dni, standardna navodila za kompas sever / jug / vzhod / zahod, apoene kovancev valute in vrste žetonov leksikalnega analizatorja.

Našteti tipi se tradicionalno izvajajo kot zaporedja celoštevilčnih konstant, kar dokazuje naslednji sklop konstant konstant:

statični končni int DIR_NORTH = 0; statični končni int DIR_WEST = 1; statični končni int DIR_EAST = 2; statični končni int DIR_SOUTH = 3;

Ta pristop ima več težav:

  • Pomanjkanje tipske varnosti: Ker je oštevilčena konstanta tipa samo celo število, lahko določite katero koli celo število, kjer je potrebna konstanta. Poleg tega lahko na teh konstantah izvajamo seštevanje, odštevanje in druge matematične operacije; na primer, (DIR_NORTH + DIR_EAST) / DIR_SOUTH), kar je nesmiselno.
  • Imenski prostor ni prisoten: Konstante naštetega tipa morajo imeti predpono z nekakšnim (upajmo) enoličnim identifikatorjem (npr. DIR_), da se prepreči trčenje s konstantami drugega naštetega tipa.
  • Krhkost: Ker se naštete konstante tipa prevedejo v datoteke razredov, kjer so shranjene njihove dobesedne vrednosti (v konstantnih področjih), spreminjanje vrednosti konstante zahteva, da se te datoteke razredov in tiste datoteke razreda aplikacij, ki so odvisne od njih, obnovijo. V nasprotnem primeru se med izvajanjem zgodi nedefinirano vedenje.
  • Pomanjkanje informacij: Ko je konstanta natisnjena, se izpiše njena celoštevilska vrednost. Ta izhod vam nič ne pove o tem, kaj predstavlja celoštevilska vrednost. Niti ne identificira naštetega tipa, ki mu pripada konstanta.

Z uporabo se lahko izognete težavam s "pomanjkanjem varnosti tipa" in "pomanjkanjem informacij" java.lang.String konstante. Lahko na primer določite statični končni niz DIR_NORTH = "NORTH";. Čeprav je konstantna vrednost bolj smiselna, Vrvicakonstante na osnovi še vedno trpijo zaradi "imenskega prostora ni" in krhkosti. Prav tako v nasprotju s primerjavami celih števil ne morete primerjati nizov z vrednostjo == in != operaterji (ki primerjajo samo reference).

Te težave so povzročile, da so razvijalci izumili alternativo, ki temelji na razredu, znano kot Typesafe Enum. Ta vzorec je bil široko opisan in kritiziran. Joshua Bloch je vzorec predstavil v 21. točki Učinkovit vodnik po programskem jeziku Java (Addison-Wesley, 2001) in opozoril, da ima nekaj težav; namreč neprijetno je združevanje tipov varnih enum konstant v nabore in da konstante štetja ni mogoče uporabiti v stikalo izjave.

Razmislite o naslednjem primeru vzorca enum typesafe. The Obleka class prikazuje, kako lahko z alternativo, ki temelji na razredu, uvedete oštevilčen tip, ki opisuje štiri mape kart (palice, diamanti, srca in pike):

javni končni razred Suit // Suit ne bi smel biti sposoben podrazreda. {javni statični končni Suit CLUBS = nov Suit (); javna statična končna obleka DIAMONTI = nova obleka (); javna statična končna obleka SRCA = nova obleka (); javna statična končna obleka SPADES = nova obleka (); private Suit () {} // Ne bi smel biti sposoben uvesti dodatnih konstant. }

Če želite uporabiti ta razred, bi uvedli Obleka spremenljivko in jo dodelite enemu od OblekaKonstante, kot sledi:

Suit suit = Suit.DIAMONDS;

Potem boste morda želeli zaslišati obleko v stikalo izjava, kot je ta:

stikalo (obleka) {primer Suit.CLUBS: System.out.println ("klubi"); odmor; zadeva Suit.DIAMONDS: System.out.println ("diamanti"); odmor; zadeva Suit.HEARTS: System.out.println ("srca"); odmor; zadeva Suit.SPADES: System.out.println ("pike"); }

Ko pa naleti prevajalnik Java Obleka.KLUBI, poroča o napaki, ki navaja, da je potreben konstanten izraz. Težavo lahko poskusite odpraviti na naslednji način:

stikalo (obleka) {case KLUBI: System.out.println ("klubi"); odmor; ohišje DIAMANTI: System.out.println ("diamanti"); odmor; zadeva SRCA: System.out.println ("srca"); odmor; zadeva SPADES: System.out.println ("pike"); }

Ko pa prevajalnik naleti KLUBI, bo sporočil napako z navedbo, da simbola ni mogel najti. Pa tudi če ste postavili Obleka v paketu uvozi paket in statično uvozi te konstante, se prevajalnik pritoži, da ne more pretvoriti Obleka do int ob srečanju obleko v stikalo (obleka). Glede vsakega Ovitek, prevajalnik bi tudi poročal, da je potreben konstanten izraz.

Java ne podpira vzorca Typesafe Enum z stikalo izjave. Vendar pa je predstavil typesafe enum funkcija jezika, da zajema prednosti vzorca med reševanjem njegovih težav in ta funkcija podpira stikalo.

Deklariranje tipskega števila in njegovo uporabo v stavku switch

Preprosta deklaracija enum typesafe v kodo Java je videti podobna v jezikih C, C ++ in C #:

enum Smer {SEVER, ZAHOD, VZHOD, JUG}

Ta izjava uporablja ključno besedo enum predstaviti Smer kot typesafe enum (posebna vrsta razreda), v katerem je mogoče dodati poljubne metode in uporabiti poljubne vmesnike. The SEVER, ZAHOD, VZHOD, in JUGenum konstante se izvajajo kot telesa specifičnih razredov, ki določajo anonimne razrede, ki razširjajo pripenjanje Smer razred.

Smer in drugi tipi varnih naštevanj se razširijo Enum in podedujejo različne metode, vključno z vrednote(), toString (), in compareTo (), iz tega razreda. Bomo raziskali Enum kasneje v tem članku.

Seznam 1 navaja zgoraj omenjeno naštevanje in ga uporabi v stikalo izjavo. Prav tako prikazuje, kako primerjati dve konstanti enum in določiti, katera konstanta je pred drugo konstanto.

Seznam 1: TEDemo.java (različica 1)

javni razred TEDemo {enum Direction {NORTH, WEST, EAST, SOUTH} public static void main (String [] args) {for (int i = 0; i <Direction.values ​​(). length; i ++) {Direction d = Direction .values ​​() [i]; System.out.println (d); stikalo (d) {case NORTH: System.out.println ("Premakni se proti severu"); odmor; primer WEST: System.out.println ("Premakni se proti zahodu"); odmor; primer EAST: System.out.println ("Premakni se proti vzhodu"); odmor; primer JUG: System.out.println ("Premakni se proti jugu"); odmor; privzeto: trditev false: "neznana smer"; }} System.out.println (Direction.NORTH.compareTo (Direction.SOUTH)); }}

Seznam 1 označuje Smer typesafe enum in se ponovi nad njegovimi stalnimi člani, ki vrednote() vrne. Za vsako vrednost je stikalo stavek (izboljšan za podporo varnim naštevanjem) izbere Ovitek ki ustreza vrednostid in prikaže ustrezno sporočilo. (Pred konstanto enum ne vnesete predpone, npr. SEVER, s svojo vrsto enum.) Nazadnje, seznam 1 oceni Direction.NORTH.compareTo (Direction.SOUTH) da ugotovi, ali SEVER pride prej JUG.

Izvorno kodo sestavite na naslednji način:

javac TEDemo.java

Zaženite sestavljeno aplikacijo na naslednji način:

java TEDemo

Upoštevati morate naslednje rezultate:

SEVER Pomik proti severu ZAHOD Pomik proti zahodu VZHOD Pomik proti vzhodu JUG Pomik proti jugu -3

Rezultat razkriva, da je podedovano toString () metoda vrne ime konstante enum in to SEVER pride prej JUG v primerjavi s temi konstantami naštevanja.

Dodajanje podatkov in vedenj v varno naštevanje

Varnostnemu naštevanju lahko dodate podatke (v obliki polj) in vedenja (v obliki metod). Recimo, da morate na primer uvesti enum za kanadske kovance in da mora ta razred zagotavljati sredstva za vrnitev števila nikljev, drobižev, četrtin ali dolarjev, ki jih vsebuje poljubno število penijev. Seznam 2 prikazuje, kako to nalogo izvesti.

Seznam 2: TEDemo.java (različica 2)

enum Coin {NICKEL (5), // konstante se morajo najprej pojaviti DIME (10), QUARTER (25), DOLLAR (100); // podpičje je obvezno private final int valueInPennies; Coin (int valueInPennies) {this.valueInPennies = valueInPennies; } int toCoins (int pennies) {return pennies / valueInPennies; }} javni razred TEDemo {public static void main (String [] args) {if (args.length! = 1) {System.err.println ("uporaba: java TEDemo amountInPennies"); vrnitev; } int pennies = Integer.parseInt (args [0]); for (int i = 0; i <Coin.values ​​(). length; i ++) System.out.println (penijev + "penijev vsebuje" + Coin.values ​​() [i] .toCoins (penijev) + "" + Coin .values ​​() [i] .toString (). toLowerCase () + "s"); }}

Seznam 2 najprej navaja a Kovanec enum. Seznam parametriziranih konstant opredeljuje štiri vrste kovancev. Argument, poslan vsaki konstanti, predstavlja število penijev, ki jih predstavlja kovanec.

Argument, poslan vsaki konstanti, se dejansko posreduje Kovanec (int valueInPennies) konstruktor, ki argument shrani v valuesInPennies polje primerka. Do te spremenljivke dostopate znotraj toCoins () metoda primerka. Deli se na število penijev, ki so jim bili predani toCoin ()"s penijev in ta metoda vrne rezultat, ki je število kovancev v denarnem apoenu, ki ga opisuje Kovanec konstanten.

Na tej točki ste odkrili, da lahko prijavite polja primerkov, konstruktorje in metode primerka v varnem tipu. Navsezadnje je typesafe enum v bistvu posebna vrsta razreda Java.

The TEDemo razreda glavni () metoda najprej preveri, ali je podan en argument ukazne vrstice. Ta argument se pretvori v celo število s klicem java.lang.Integer razreda parseInt () metoda, ki vrednost argumenta niza razčleni na celo število (ali vrže izjemo, ko je zaznan neveljaven vnos). O tem bom imel več povedati Celo število in njegovi bratranci v prihodnosti Java 101 Članek.

Premikanje naprej, glavni () se ponavlja KovanecKonstante. Ker so te konstante shranjene v Kovanec [] matrika, glavni () ocenjuje Coin.values ​​(). Dolžina za določitev dolžine te matrike. Za vsako ponovitev indeksa zanke jaz, glavni () ocenjuje Coin.values ​​() [i] za dostop do Kovanec konstanten. Prikliče vsakega od toCoins () in toString () na tej konstanti, kar še dokazuje, da Kovanec je posebna vrsta pouka.

Izvorno kodo prevedite na naslednji način:

javac TEDemo.java

Zaženite sestavljeno aplikacijo, kot sledi:

java TEDemo 198

Upoštevati morate naslednje rezultate:

198 penijev vsebuje 39 nikljev 198 penijev vsebuje 19 drobižev 198 penijev vsebuje 7 četrtin 198 penijev vsebuje 1 dolar

Raziskovanje Enum razred

Prevajalnik Java meni enum biti skladenjski sladkor. Ko naleti na deklaracijo typesafe enum, generira razred, katerega ime je določeno z deklaracijo. Ta razred podrazredi abstrakt Enum class, ki služi kot osnovni razred za vse naštete vrste.

EnumFormalni seznam parametrov tipa je grozljiv, vendar ga ni tako težko razumeti. Na primer v kontekstu Kovanec podaljša Enum, ta formalni seznam parametrov tipa bi razlagali takole:

  • Kateri koli podrazred Enum mora navesti dejanski argument tipa Enum. Na primer, KovanecGlava določa Enum.
  • Dejanski argument tipa mora biti podrazred Enum. Na primer, Kovanec je podrazred Enum.
  • Podrazred Enum (kot naprimer Kovanec) mora slediti idiomu, da navede svoje ime (Kovanec) kot dejanski argument tipa.

Preuči EnumDokumentacijo Java in odkrili boste, da preglasi java.lang.Objectje klon (), enako (), dokončaj (), hashCode (), in toString () metode. Razen toString (), so razglašene vse te nadrejene metode dokončno tako da jih ni mogoče preglasiti v podrazredu:

  • klon () je nadomeščen, da se prepreči kloniranje konstant, tako da ni nikoli več kot ena kopija konstante; sicer konstante ni bilo mogoče primerjati z == in !=.
  • enako () je nadomeščen za primerjavo konstant prek njihovih referenc. Konstante z enakimi identitetami (==) mora imeti enako vsebino (enako ()), različne identitete pa pomenijo različne vsebine.
  • dokončaj () je nadomeščen, da se zagotovi, da konstante ni mogoče določiti.
  • hashCode () je razveljavljeno, ker enako () je razveljavljeno.
  • toString () je nadomeščeno, da vrne ime konstante.

Enum ponuja tudi lastne metode. Te metode vključujejo dokončnocompareTo () (Enum izvaja java.lang.Primerljivo vmesnik), getDeclaringClass (), ime (), in redni () metode:

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