Java kods, kas izmanto tradicionālos uzskaitītos veidus, ir problemātisks. Java 5 deva mums labāku alternatīvu veidu drukāto uzrakstu veidā. Šajā rakstā es jūs iepazīstinu ar uzskaitītajiem tipiem un tipofe uzskaitījumiem, parādīšu, kā pasludināt typefe enum un izmantot to switch paziņojumā, kā arī apspriest typeafe enum pielāgošanu, pievienojot datus un uzvedību. Es iesaiņoju rakstu, izpētot java.lang.Enum
klasē.
Sākot no uzskaitītajiem tipiem un beidzot ar tipafe
An uzskaitītais tips kā vērtības norāda saistīto konstantu kopu. Piemēri ietver dienu nedēļu, standarta ziemeļu / dienvidu / austrumu / rietumu kompasa virzienus, valūtas monētu nominālvērtības un leksiskā analizatora žetonu veidus.
Uzskaitītie tipi tradicionāli tiek ieviesti kā veselu skaitļu konstantu sekvences, ko pierāda šāda virziena konstante:
statiskā gala int DIR_NORTH = 0; statiskais gala int DIR_WEST = 1; statiskais gala int DIR_EAST = 2; statiskais gala int DIR_SOUTH = 3;
Šai pieejai ir vairākas problēmas:
- Tipa drošības trūkums: Tā kā uzskaitītā tipa konstante ir tikai vesels skaitlis, jebkuru skaitli var norādīt, kur konstante ir nepieciešama. Turklāt šīm konstantēm var veikt saskaitīšanas, atņemšanas un citas matemātikas darbības; piemēram,
(DIR_NORTH + DIR_EAST) / DIR_SOUTH
), kas ir bezjēdzīgi. - Vārdvietas nav: Uzskaitīta tipa konstantēm jābūt prefiksiem ar sava veida (cerams) unikālu identifikatoru (piem.,
DIR_
), lai novērstu sadursmes ar cita uzskaitītā tipa konstantēm. - Trauslums: Tā kā uzskaitītās tipa konstantes tiek apkopotas klases failos, kur to burtiskās vērtības tiek glabātas (nemainīgos baseinos), mainot konstantes vērtību, šie klases faili un no tiem atkarīgie lietojumprogrammu klases faili ir jāatjauno. Pretējā gadījumā nedefinēta uzvedība notiks izpildlaikā.
- Informācijas trūkums: Kad tiek izdrukāta konstante, tiek izvadīta tās veselā skaitļa vērtība. Šis izvade jums neko nepasaka par to, ko apzīmē vesela skaitļa vērtība. Tas pat nenosaka uzskaitīto tipu, kuram pieder konstante.
Izmantojot, jūs varētu izvairīties no “tipa drošības trūkuma” un “informācijas trūkuma” problēmām java.lang.Strings
konstantes. Piemēram, jūs varat norādīt statiskā galīgā virkne DIR_NORTH = "NORTH";
. Lai gan nemainīgā vērtība ir nozīmīgāka, Stīga
konstantes joprojām cieš no “vārda vietas nav” un trausluma problēmām. Tāpat atšķirībā no veselu skaitļu salīdzinājumiem, virknes vērtības nevar salīdzināt ar ==
un !=
operatori (kuri salīdzina tikai atsauces).
Šīs problēmas lika izstrādātājiem izgudrot uz klasēm balstītu alternatīvu, kas pazīstama kā Typesafe Enum. Šis modelis ir plaši aprakstīts un kritizēts. Džošua Blohs ieviesa paraugu sava 21. punktā Efektīva Java programmēšanas valodas rokasgrāmata (Addison-Wesley, 2001) un atzīmēja, ka tam ir dažas problēmas; proti, ka ir neērti apkopot typeafe enum konstantes kopās un ka uzskaites konstantes nevar izmantot slēdzis
paziņojumi.
Apsveriet šādu tipsafe enum modeļa piemēru. The Uzvalks
klase parāda, kā jūs varētu izmantot klases alternatīvu, lai ieviestu uzskaitītu veidu, kas raksturo četrus kāršu uzvalkus (nūjas, dimantus, sirdis un lāpstas):
public final class Suit // Nevajadzētu spēt apakšklasē Suit. {public static final Suit CLUBS = jauns uzvalks (); public static final Suit DIAMONDS = new Uzvalks (); public static final Suit HEARTS = new Uzvalks (); public static final Suit SPADES = new Uzvalks (); privāts uzvalks () {} // nevajadzētu būt iespējai ieviest papildu konstantes. }
Lai izmantotu šo klasi, jūs ieviestu a Uzvalks
mainīgo un piešķir to vienam no Uzvalks
Šādas konstantes:
Uzvalka uzvalks = Uzvalks.DIAMONDS;
Tad jūs varētu vēlēties nopratināt uzvalks
iekšā slēdzis
šāds paziņojums:
slēdzis (uzvalks) {gadījums Suit.CLUBS: System.out.println ("klubi"); pārtraukums; korpuss Suit.DIAMONDS: System.out.println ("dimanti"); pārtraukums; lieta Suit.HEARTS: System.out.println ("sirdis"); pārtraukums; korpuss Suit.SPADES: System.out.println ("lāpstas"); }
Tomēr, kad Java kompilators sastopas Uzvalks. KLUBI
, tā ziņo par kļūdu, norādot, ka ir nepieciešama pastāvīga izteiksme. Jūs varētu mēģināt risināt problēmu šādi:
slēdzis (uzvalks) {case CLUBS: System.out.println ("klubi"); pārtraukums; korpuss DIAMONDI: System.out.println ("dimanti"); pārtraukums; gadījums SIRDS: System.out.println ("sirdis"); pārtraukums; gadījums SPADES: System.out.println ("lāpstas"); }
Tomēr, kad sastādītājs sastopas KLUBI
, tā ziņos par kļūdu, norādot, ka tā nevarēja atrast simbolu. Un pat ja jūs ievietojat Uzvalks
paketē, importēja paketi un statiski importēja šīs konstantes, kompilators sūdzas, ka nevar pārveidot Uzvalks
uz int
sastopoties uzvalks
iekšā slēdzis (uzvalks)
. Attiecībā uz katru gadījumā
, sastādītājs arī ziņo, ka ir nepieciešama pastāvīga izteiksme.
Java neatbalsta tipu Typesafe Enum ar slēdzis
paziņojumi. Tomēr tas tomēr ieviesa typesafe enum valodas iezīme, lai apkopotu modeļa priekšrocības, vienlaikus risinot tā problēmas, un šī funkcija atbalsta slēdzis
.
Deklarējot typeafe enum un izmantojot to switch paziņojumā
Vienkārša Java koda tipsafe enum deklarācija izskatās kā tās kolēģi C, C ++ un C # valodās:
enum Virziens {NORTH, WEST, EAST, SOUTH}
Šajā deklarācijā tiek izmantots atslēgvārds enum
iepazīstināt Virziens
kā typeafe enum (īpaša veida klase), kurā var pievienot patvaļīgas metodes un ieviest patvaļīgas saskarnes. The ZIEMEĻA
, RIETUMI
, AUSTRUMI
, un DIENVIDI
enum konstantes tiek ieviesti kā nemainīgām specifiskām klases struktūrām, kas nosaka anonīmās klases, paplašinot norobežojošo Virziens
klasē.
Virziens
un citu veidu seifu saraksti paplašinās Enum
un pārmantot dažādas metodes, ieskaitot vērtības ()
, toString ()
, un Salīdzinot ar()
, no šīs klases. Mēs izpētīsim Enum
vēlāk šajā rakstā.
1. saraksts deklarē iepriekšminēto uzskaitījumu un izmanto to a slēdzis
paziņojums, apgalvojums. Tas arī parāda, kā salīdzināt divas uzskaites konstantes, lai noteiktu, kura konstante nāk pirms citas konstantas.
1. saraksts: TEDemo.java
(1. versija)
public class 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 .vērtības () [i]; System.out.println (d); slēdzis (d) {gadījums NORTH: System.out.println ("Pārvietoties uz ziemeļiem"); pārtraukums; gadījums WEST: System.out.println ("Pārvietoties uz rietumiem"); pārtraukums; gadījums EAST: System.out.println ("Pārvietoties uz austrumiem"); pārtraukums; gadījums SOUTH: System.out.println ("Pārvietoties uz dienvidiem"); pārtraukums; noklusējums: apgalvot nepatiesu: "nezināms virziens"; }} System.out.println (Direction.NORTH.compareTo (Direction.SOUTH)); }}
1. saraksts deklarē Virziens
tipsafe enum un atkārto savus pastāvīgos locekļus, kas vērtības ()
atgriežas. Katrai vērtībai slēdzis
paziņojums (uzlabots, lai atbalstītu tipafe enums) izvēlas gadījumā
kas atbilstd
un izdod atbilstošu ziņojumu. (Jums nav prefiksa enum konstante, piem., ZIEMEĻA
, ar tā uzskaites veidu.) Visbeidzot, 1. sarakstā tiek novērtēts Direction.NORTH.compareTo (Direction.SOUTH)
lai noteiktu, vai ZIEMEĻA
nāk pirms DIENVIDI
.
Apkopojiet avota kodu šādi:
javac TEDemo.java
Palaidiet apkopoto lietojumprogrammu šādi:
java TEDemo
Jums jāievēro šāda izeja:
ZIEMEĻI Pārvietojieties uz ziemeļiem uz rietumiem Pārvietojieties uz rietumiem EAST Pārvietojieties uz austrumiem DAUDZ virzieties uz dienvidiem -3
Rezultāts atklāj, ka mantots toString ()
metode atgriež uzskaites konstantes nosaukumu un to ZIEMEĻA
nāk pirms DIENVIDI
salīdzinot šīs enum konstantes.
Datu un uzvedības pievienošana tipafe enum
Datus (lauku veidā) un uzvedību (metožu veidā) jūs varat pievienot tipafe sarakstam. Piemēram, pieņemsim, ka jums ir jāievada Kanādas monētu uzskaite un ka šai klasei ir jānodrošina līdzekļi, lai atgrieztu niķeļu, dimeju, ceturtdaļu vai dolāru skaitu patvaļīgā pensu skaitā. 2. saraksts parāda, kā izpildīt šo uzdevumu.
2. saraksts: TEDemo.java
(2. versija)
enum Monēta {NICKEL (5), // konstantēm vispirms jāparādās DIME (10), QUARTER (25), DOLLAR (100); // semikols ir nepieciešams private final int valueInPennies; Monēta (int valueInPennies) {this.valueInPennies = valueInPennies; } int toCoins (int pennies) {return pennies / valueInPennies; }} public class TEDemo {public static void main (String [] args) {if (args.length! = 1) {System.err.println ("lietojums: java TEDemo summaInPennies"); atgriešanās; } int santīmi = Integer.parseInt (args [0]); par (int i = 0; i <Monētu vērtības (). garums; i ++) System.out.println (santīmi + "santīmos ir" + Monētas.vērtības () [i] .toCoins (santīmus) + "" + Monēta .values () [i] .toString (). toLowerCase () + "s"); }}
2. saraksts vispirms deklarē a Monēta
enum. Parametrētu konstantu sarakstā ir identificēti četri monētu veidi. Katrai konstantei nodotais arguments norāda monētu pārstāvēto santīmu skaitu.
Katrai konstantei nodotais arguments faktiski tiek nodots Monēta (int valueInPennies)
konstruktors, kas saglabā argumentu vērtībasInPennies
instances lauks. Šim mainīgajam var piekļūt no monētas ()
instances metode. Tas tiek sadalīts pensu skaitā, kas nodoti toCoin ()
’S santīmus
parametrs, un šī metode atgriež rezultātu, kas, iespējams, ir monētu skaits naudas nominālvērtībā, ko apraksta Monēta
nemainīgs.
Šajā brīdī jūs esat atklājis, ka jūs varat deklarēt eksemplāru laukus, konstruktorus un instanču metodes tipa drukas sarakstā. Galu galā, typeafe enum būtībā ir īpašs Java klases veids.
The TEDemo
klases galvenais ()
metode vispirms pārbauda, vai ir norādīts viens komandrindas arguments. Šis arguments tiek pārveidots par veselu skaitli, izsaucot java.lang.Integer
klases parseInt ()
metodi, kas parsē virknes argumenta vērtību veselā skaitlī (vai izmet izņēmumu, ja tiek konstatēta nederīga ievade). Man būs vairāk ko teikt Vesels skaitlis
un tās brālēnu klases nākotnē Java 101 rakstu.
Virzīties uz priekšu, galvenais ()
atkārtojas Monēta
Konstantes. Tā kā šīs konstantes tiek glabātas a Monēta []
masīvs, galvenais ()
novērtē Monēta.vērtības (). Garums
lai noteiktu šī masīva garumu. Katrai cilpas indeksa iterācijai i
, galvenais ()
novērtē Monētu vērtības () [i]
lai piekļūtu Monēta
nemainīgs. Tas atsaucas uz katru no monētas ()
un toString ()
uz šīs konstantes, kas to vēl vairāk pierāda Monēta
ir īpaša klases klase.
Apkopojiet avota kodu šādi:
javac TEDemo.java
Palaidiet apkopoto lietojumprogrammu šādi:
java TEDemo 198
Jums jāievēro šāda izeja:
198 pennies satur 39 niķeļus. 198 pennies satur 19 dimes. 198 pennies satur 7 ceturtdaļas. 198 pennies satur 1 dolāru
Izpētīt Enum
klasē
Java kompilators apsver enum
lai tas būtu sintaktiskais cukurs. Sastopoties ar typeafe enum deklarāciju, tā ģenerē klasi, kuras nosaukums ir norādīts deklarācijā. Šajā klasē apakšklase ir abstrakta Enum
klase, kas kalpo kā bāzes klase visu veidu seifiem.
Enum
Formālais parametru saraksts izskatās šausmīgi, taču to nav tik grūti saprast. Piemēram, kontekstā Monēta pagarina Enum
, jūs šo oficiālo tipu parametru sarakstu interpretētu šādi:
- Jebkura
Enum
jānorāda faktiskā tipa argumentsEnum
. Piemēram,Monēta
Galvene norādaEnum
. - Faktiskajam argumenta tipam jābūt
Enum
. Piemēram,Monēta
ir apakšklaseEnum
. - Apakšklase
Enum
(piemēram,Monēta
) jāievēro idioma, ka tā piegādā savu vārdu (Monēta
) kā faktiskā tipa arguments.
Pārbaudiet Enum
Java dokumentāciju, un jūs atklāsiet, ka tā tiek ignorēta java.lang.Object
's klons ()
, vienāds ()
, pabeigt ()
, hashCode ()
, un toString ()
metodes. Izņemot toString ()
, tiek deklarētas visas šīs svarīgākās metodes galīgais
lai tos nevarētu ignorēt apakšklasē:
klons ()
tiek ignorēts, lai novērstu konstantu klonēšanu, lai nekad nebūtu vairāk par vienu konstantes kopiju; pretējā gadījumā konstantes nevarēja salīdzināt==
un!=
.vienāds ()
tiek ignorēts, lai salīdzinātu konstantes, izmantojot to atsauces. Konstantes ar vienādām identitātēm (==
) jābūt vienādam (vienāds ()
), un atšķirīgas identitātes nozīmē atšķirīgu saturu.pabeigt ()
tiek ignorēts, lai nodrošinātu, ka konstantes nevar pabeigt.hashCode ()
tiek ignorēts, jovienāds ()
tiek ignorēts.toString ()
tiek ignorēts, lai atgrieztu konstantes vārdu.
Enum
sniedz arī savas metodes. Šīs metodes ietver galīgais
Salīdzinot ar()
(Enum
īsteno java.lang.Salīdzināms
interfeiss), getDeclaringClass ()
, nosaukums ()
, un kārtas numurs ()
metodes: