Programmēšana

Java izveidojiet uzskaitītas konstantes

"Neskaitāmu konstanšu" kopa ir sakārtota konstantu kolekcija, kuras var saskaitīt, piemēram, skaitļus. Šis rekvizīts ļauj tos izmantot kā skaitļus masīva indeksēšanai, vai arī jūs varat tos izmantot kā indeksa mainīgo for ciklā. Java valodā šādus objektus visbiežāk sauc par "uzskaitītām konstantēm".

Izmantojot uzskaitītas konstantes, kods var būt lasāmāks. Piemēram, kā iespējamās vērtības, iespējams, vēlēsities definēt jaunu datu tipu ar nosaukumu Krāsa ar RED, GREEN un BLUE konstantēm. Ideja ir, lai krāsa kā citu jūsu izveidotu objektu, piemēram, automašīnu objektu, atribūts būtu:

 klases automašīna {Krāsas krāsa; ...} 

Tad jūs varat uzrakstīt skaidru un salasāmu kodu šādi:

 myCar.color = RED; 

nevis kaut kā:

 myCar.color = 3; 

Vēl svarīgāks uzskaitīto konstanšu atribūts tādās valodās kā Pascal ir tas, ka tās ir tipa drošas. Citiem vārdiem sakot, krāsas atribūtam nav iespējams piešķirt nederīgu krāsu - tai vienmēr jābūt vai nu SARKANAI, ZAĻAI vai ZILAI. Turpretī, ja krāsu mainīgais būtu int, tad tam varētu piešķirt jebkuru derīgu veselu skaitli, pat ja šis skaitlis neatspoguļo derīgu krāsu.

Šajā rakstā ir sniegta veidne, kā izveidot uzskaitītas konstantes, kas ir:

  • Ierakstiet seifu
  • Drukājams
  • Pasūtīts, izmantošanai kā indekss
  • Saistīts, lai izveidotu cilpu uz priekšu vai atpakaļ
  • Neskaitāmi

Nākamajā rakstā jūs uzzināsiet, kā paplašināt uzskaitītās konstantes, lai ieviestu no valsts atkarīgu uzvedību.

Kāpēc neizmantot statiskos finālus?

Kopīgs uzskaitīto konstantu mehānisms izmanto statiskos galīgos int mainīgos, piemēram:

 statiskais gala int RED = 0; statiskā gala int ZAĻA = 1; statiskais gala int BLUE = 2; ... 

Statiskie fināli ir noderīgi

Tā kā tās ir galīgas, vērtības ir nemainīgas un nemainīgas. Tā kā tie ir statiski, tie tiek izveidoti tikai vienai kategorijai vai saskarnei, kurā tie ir definēti, nevis vienu reizi katram objektam. Tā kā tie ir veseli skaitļi, tos var uzskaitīt un izmantot kā indeksu.

Piemēram, varat uzrakstīt cilpu, lai izveidotu klienta iecienītāko krāsu sarakstu:

 par (int i = 0; ...) {if (customerLikesColor (i)) {favoriteColors.add (i); }} 

Varat arī indeksēt masīvā vai vektorā, izmantojot mainīgos, lai iegūtu vērtību, kas saistīta ar krāsu. Piemēram, pieņemsim, ka jums ir galda spēle, kurā katram spēlētājam ir dažādas krāsas gabali. Pieņemsim, ka jums ir katras krāsas gabala bitkarte un tā sauktā metode displejs () kas kopē šo bitkarti pašreizējā vietā. Viens veids, kā ievietot gabalu uz tāfeles, varētu būt apmēram šāds:

PiecePicture redPiece = jauns PiecePicture (RED); PiecePicture greenPiece = jauna PiecePicture (ZAĻA); PiecePicture bluePiece = jauns PiecePicture (ZILS);

void placePiece (int atrašanās vieta, int krāsa) {setPosition (atrašanās vieta); ja (krāsa == RED) {displejs (redPiece); } else if (krāsa == ZAĻA) {display (greenPiece); } else {display (bluePiece); }}

Bet, izmantojot veselu skaitļu vērtības, lai indeksētu gabalu masīvā, kodu var vienkāršot šādi:

 PiecePicture [] piece = {jauns PiecePicture (RED), jauns PiecePicture (GREEN), jauns PiecePicture (BLUE)}; void placePiece (int atrašanās vieta, int krāsa) {setPosition (atrašanās vieta); displejs (gabals [krāsa]); } 

Galvenā statisko galīgo veselu skaitļu priekšrocība ir iespēja konvertēt konstantes un indeksēt masīvā vai vektorā. Un, kad izvēles skaits pieaug, vienkāršošanas efekts ir vēl lielāks.

Bet statiskie fināli ir riskanti

Tomēr statisko galīgo skaitļu izmantošanā ir pāris trūkumi. Galvenais trūkums ir tipa drošības trūkums. Jebkuru skaitli, kas tiek aprēķināts vai nolasīts, var izmantot kā "krāsu" neatkarīgi no tā, vai tas ir jēga to darīt. Varat veikt cilpu tieši aiz definēto konstantu beigām vai apstāties, lai tos visus neaptvertu, kas var viegli notikt, ja pievienojat vai noņemat konstanti no saraksta, bet aizmirstat pielāgot cilpas indeksu.

Piemēram, jūsu krāsu izvēles cilpa varētu būt šāda:

 par (int i = 0; i <= ZILS; i ++) {if (klientamPatīkColor (i)) {favoriteColors.add (i); }} 

Vēlāk jūs varat pievienot jaunu krāsu:

 statiskais gala int RED = 0; statiskā gala int ZAĻA = 1; statiskais gala int BLUE = 2; statiskais gala int MAGENTA = 3; 

Vai arī jūs varat noņemt vienu:

 statiskais gala int RED = 0; statiskais gala int BLUE = 1; 

Jebkurā gadījumā programma nedarbosies pareizi. Noņemot krāsu, tiks parādīta izpildlaika kļūda, kas pievērš uzmanību problēmai. Pievienojot krāsu, jūs vispār nesaņemsit kļūdu - programma vienkārši nespēs aptvert visas krāsu izvēles iespējas.

Vēl viens trūkums ir lasāma identifikatora trūkums. Ja izmantojat ziņojumu lodziņu vai konsoles izvadi, lai parādītu pašreizējo krāsu izvēli, jūs saņemat numuru. Tas padara atkļūdošanu diezgan sarežģītu.

Dažreiz lasāmā identifikatora izveidošanas problēmas tiek atrisinātas, izmantojot statiskas galīgo virkņu konstantes, piemēram:

 statiskā gala virkne RED = "sarkana". iekšējā (); ... 

Izmantojot interns () metode garantē, ka iekšējā virkņu pūlā ir tikai viena virkne ar šo saturu. Bet par interns () Lai tā būtu efektīva, tai ir jāizmanto katra virkne vai virknes mainīgais, kas jebkad tiek salīdzināts ar RED. Pat tad statiskās pēdējās virknes neļauj izveidot ciklu vai indeksēt masīvā, un tās joprojām neatrisina tipa drošības jautājumu.

Tipa drošība

Statisko galīgo skaitļu problēma ir tāda, ka mainīgie, kas tos izmanto, pēc savas būtības nav ierobežoti. Tie ir int mainīgie, kas nozīmē, ka tie var saturēt jebkuru veselu skaitli, ne tikai konstantes, kuras viņiem bija paredzēts turēt. Mērķis ir definēt krāsu veida mainīgo, lai iegūtu mainīšanas kļūdu, nevis izpildlaika kļūdu ikreiz, kad šim mainīgajam tiek piešķirta nederīga vērtība.

Elegants risinājums tika sniegts Filipa Bišopa rakstā JavaWorld "Typesafe konstanti C ++ un Java".

Ideja ir patiešām vienkārša (tiklīdz to redzat!):

publiskā fināla klase Krāsa {// fināla klase !! privāts Krāsa () {} // privāts konstruktors !!

publiskā statiskā galīgā krāsa RED = jauna krāsa (); public static final Krāsa ZAĻA = jauna Krāsa (); public static final Krāsa ZILA = jauna krāsa (); }

Tā kā klase ir definēta kā galīga, to nevar apakšklasīt. No tā netiks izveidotas citas klases. Tā kā konstruktors ir privāts, citas metodes nevar izmantot klasi jaunu objektu veidošanai. Vienīgie objekti, kas jebkad tiks izveidoti ar šo klasi, ir statiskie objekti, kurus klase sev izveido, pirmo reizi atsaucoties uz klasi! Šī ieviešana ir Singletona modeļa variācija, kas ierobežo klasi ar iepriekš noteiktu gadījumu skaitu. Jūs varat izmantot šo modeli, lai izveidotu tieši vienu klasi jebkurā laikā, kad jums nepieciešams Singleton, vai izmantojiet to, kā parādīts šeit, lai izveidotu noteiktu skaitu gadījumu. (Singletona modelis ir definēts grāmatā Dizaina modeļi: atkārtoti lietojamas objektorientētas programmatūras elementi autori Gamma, Helms, Džonsons un Vlisīds, Adisona-Veslija, 1995. Saiti uz šo grāmatu skatiet sadaļā Resursi.)

Šīs klases definīcijas prātam neaptveramā daļa ir tā, ko klase izmanto pati lai izveidotu jaunus objektus. Pirmo reizi atsaucoties uz RED, tā nepastāv. Bet piekļuves darbība klasei, kurā RED ir definēts, liek to izveidot kopā ar citām konstantēm. Jāatzīst, ka šāda veida rekursīvas atsauces ir diezgan grūti vizualizēt. Bet priekšrocība ir kopējā tipa drošība. Krāsu tipa mainīgajam nekad nevar piešķirt neko citu kā RED, GREEN vai BLUE objektus, kas ir Krāsa klase rada.

Identifikatori

Pirmais tipsafe uzskaitītās nemainīgās klases uzlabojums ir izveidot konstantu virknes attēlojumu. Jūs vēlaties, lai ar šādu līniju varētu izveidot salasāmu vērtības versiju:

 System.out.println (myColor); 

Ikreiz, kad objektu izvada rakstzīmju izvades straumē, piemēram, System.out, un ikreiz, kad jūs savienojat objektu ar virkni, Java automātiski izsauc toString () metode šim objektam. Tas ir labs iemesls, lai definētu a toString () metode jebkurai jaunai klasei, kuru izveidojat.

Ja klasē nav a toString () metodi tiek pārbaudīta mantojuma hierarhija, līdz tiek atrasta. Hierarhijas augšpusē toString () metodi Objekts klase atgriež klases nosaukumu. Tātad toString () metode vienmēr ir bijusi daži nozīme, taču visbiežāk noklusējuma metode nebūs ļoti noderīga.

Šeit ir modifikācija Krāsa klase, kas nodrošina noderīgu toString () metode:

publiskā fināla klase Krāsa { privāta virknes ID; privāta krāsa (Virknes anID) {this.id = anID; } public String toString () {return this.id; }

publiskā statiskā galīgā krāsa RED = jauna krāsa (

"Sarkans"

); publiskā statiskā galīgā krāsa ZAĻA = jauna krāsa (

"Zaļš"

); publiskā statiskā galīgā krāsa ZILA = jauna krāsa (

"Zils"

); }

Šī versija pievieno privātu virknes mainīgo (id). Konstruktors ir modificēts, lai ņemtu argumentu String un saglabātu to kā objekta ID. The toString () metode atgriež objekta ID.

Viens triks, kuru varat izmantot, lai izsauktu toString () metode izmanto faktu, ka tā tiek automātiski izsaukta, kad objekts tiek savienots ar virkni. Tas nozīmē, ka jūs varētu ievietot objekta nosaukumu dialoglodziņā, savienojot to ar nulles virkni, izmantojot šādu rindiņu:

 textField1.setText ("" + myColor); 

Ja vien jūs nejauši nemīlat visas iekavas Lisp, jūs atradīsit to mazliet lasāmāk nekā alternatīva:

 textField1.setText (myColor.toString ()); 

Tāpat ir vieglāk pārliecināties, vai esat ievietojis pareizo aizvērošo iekavu skaitu!

Pasūtīšana un indeksēšana

Nākamais jautājums ir, kā indeksēt vektorā vai masīvā, izmantojot

Krāsa

klasē. Mehānisms būs kārtas numura piešķiršana katrai klases konstantei un atsauce uz to, izmantojot atribūtu

.ord

, kā šis:

 void placePiece (int atrašanās vieta, int krāsa) {setPosition (atrašanās vieta); displejs (gabals [krāsa.ord]); } 

Kaut arī ķerties pie .ord pārveidot atsauci uz krāsa skaitlis nav īpaši skaists, tas nav arī ļoti uzmācīgs. Šķiet, ka tas ir diezgan pamatots kompromiss attiecībā uz tipveida drošām konstantēm.

Lūk, kā tiek piešķirti kārtas skaitļi:

publiskā fināla klase Color {private String id; public final int ord;privāts statisks int augšējaisSaistīts = 0; privāta krāsa (virknes anID) {this.id = anID; this.ord = upperBound ++; } public String toString () {return this.id; } public static int size () {return upperBound; }

publiskā statiskā galīgā krāsa RED = jauna krāsa ("sarkana"); public static final Krāsa ZAĻA = jauna krāsa ("Zaļa"); public static final Krāsa ZILA = jauna krāsa ("Zila"); }

Šis kods izmanto jauno JDK 1.1 versijas definīciju "tukšais galīgais" mainīgais - mainīgais, kuram vērtība tiek piešķirta tikai vienu reizi. Šis mehānisms ļauj katram objektam būt savam statiskajam nemainīgajam mainīgajam, ord, kas objekta izveidošanas laikā tiks piešķirts vienu reizi un kas pēc tam paliks nemainīgs. Statiskais mainīgais augšējaisSaistīts seko līdzi nākamajam neizmantotajam kolekcijas indeksam. Šī vērtība kļūst par ord atribūts, kad objekts ir izveidots, pēc kura augšējā robeža tiek palielināta.

Saderībai ar Vector klase, metode Izmērs() ir definēts, lai atgrieztu šajā klasē definēto konstantu skaitu (kas ir tāds pats kā augšējā robeža).

Pūrists varētu nolemt, ka mainīgais ord jābūt privātai, un metodei jābūt nosauktai ord () vajadzētu to atdot - ja nē, metodi, kas nosaukta getOrd (). Es tomēr sliecos tieši piekļūt atribūtam divu iemeslu dēļ. Pirmais ir tas, ka kārtas kārtas jēdziens nepārprotami ir int. Ir maz varbūtības, ja tāda vispār pastāv, ka ieviešana kādreiz mainīsies. Otrs iemesls ir tas, ko jūs patiešām gribu ir spēja izmantot objektu tā, it kā tas būtu int, kā jūs varētu tādā valodā kā Pascal. Piemēram, jūs varētu vēlēties izmantot atribūtu krāsa indeksēt masīvu. Bet tieši to nevar izmantot Java objektu. Tas, ko jūs patiešām vēlaties pateikt, ir:

 displejs (gabals [krāsa]); // vēlams, bet nedarbojas 

Bet jūs to nevarat izdarīt. Minimālās izmaiņas, kas nepieciešamas, lai iegūtu vēlamo, ir piekļuve atribūtam tā vietā:

 displejs (gabals [color.ord]); // vistuvāk vēlamajam 

garās alternatīvas vietā:

 displejs (gabals [color.ord ()]); // papildu iekavas 

vai pat garāks:

 displejs (gabals [color.getOrd ()]); // papildu iekavas un tekstu 

Eifeļa valoda izmanto to pašu sintaksi, lai piekļūtu atribūtiem un izsauktu metodes. Tas būtu ideāls. Tomēr, ņemot vērā nepieciešamību izvēlēties vienu vai otru, es esmu piekritis ord kā atribūtu. Ar jebkuru veiksmi, identifikators ord atkārtojuma rezultātā kļūs tik pazīstams, ka tā lietošana šķitīs tikpat dabiska kā rakstīšana int. (Lai cik tas dabiski nebūtu.)

Cilpošana

Nākamais solis ir spēja atkārtot klases konstantes. Jūs vēlaties, lai varētu veikt ciklu no sākuma līdz beigām:

 par (Krāsa c = Krāsa.pirmā (); c! = nulle; c = c.nākamā ()) {...} 

vai no beigām atpakaļ uz sākumu:

 par (Krāsa c = Krāsa.pēdējā (); c! = nulle; c = c.prev ()) {...} 

Šīs modifikācijas izmanto statiskos mainīgos, lai sekotu pēdējam izveidotajam objektam un saistītu to ar nākamo objektu:

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