Programmēšana

Kā izmantot Java generics, lai izvairītos no ClassCastExceptions

Java 5 ieviesa vispārīgus vārdus Java valodā. Šajā rakstā es jūs iepazīstinu ar vispārīgajiem medikamentiem un apspriežu vispārīgos veidus, vispārīgās metodes, vispārīgos un veida secinājumus, vispārīgos diskusijas, kā arī vispārīgos un kaudzes piesārņojumu.

lejupielādēt Iegūt kodu Lejupielādējiet avota kodu piemēriem šajā Java 101 apmācībā. Izveidoja Jeff Friesen JavaWorld.

Kas ir vispārīgie medikamenti?

Generics ir saistītu valodu funkciju kopums, kas ļauj tipiem vai metodēm darboties ar dažāda veida objektiem, vienlaikus nodrošinot kompilēšanas laika tipa drošību. Vispārīgās funkcijas risina java.lang.ClassCastExceptions tiek izmesti izpildlaikā, kas ir koda rezultāts, kas nav tipam drošs (t.i., objektu liešana no to pašreizējiem tipiem uz nesaderīgiem tipiem).

Generics un Java Collections Framework

Generics tiek plaši izmantoti Java Collections Framework (oficiāli ieviesti nākotnē Java 101 raksti), taču tie nav tai ekskluzīvi. Generics tiek izmantoti arī citās Java standarta klases bibliotēkas daļās, ieskaitot java.lang.Class, java.lang.Salīdzināms, java.lang.ThreadLocal, un java.lang.ref.WeakReference.

Apsveriet šādu koda fragmentu, kas parāda tipa drošības trūkumu (Java kolekciju ietvarstruktūras kontekstā) java.util.LinkedList klase), kas bija izplatīts Java kodā pirms vispārīgo ieviešanas:

Saraksts doubleList = jauns LinkedList (); doubleList.add (jauns Double (3.5)); Double d = (Double) doubleList.iterator (). Nākamais ();

Lai gan iepriekš minētās programmas mērķis ir tikai uzglabāt java.lang.Dubulta objektus sarakstā, nekas neliedz uzglabāt cita veida objektus. Piemēram, jūs varētu norādīt doubleList.add ("Labdien"); pievienot a java.lang.Strings objekts. Tomēr, uzglabājot cita veida priekšmetus, pēdējās līnijas (Dubultā) dalībnieku cēloņi ClassCastException jāmet, saskaroties ar cilvēku, kas navDubultā objekts.

Tā kā šāda veida drošības trūkums tiek atklāts tikai izpildes laikā, izstrādātājs var nezināt par problēmu, atstājot to atklāt klientam (nevis kompilatoram). Generics palīdz kompilatoram brīdināt izstrādātāju par objekta glabāšanas problēmu arDubultā ierakstiet sarakstā, ļaujot izstrādātājam atzīmēt sarakstu kā saturošu tikai Dubultā objektiem. Šī palīdzība ir parādīta zemāk:

Saraksts doubleList = jauns LinkedList (); doubleList.add (jauns Double (3.5)); Double d = doubleList.iterator (). Nākamais ();

Saraksts tagad skan “Saraksts gada Dubultā.” Saraksts ir vispārējs interfeiss, kas izteikts kā Saraksts, kas prasa a Dubultā tipa arguments, kas tiek norādīts arī, veidojot faktisko objektu. Pievienojot objektu sarakstam, kompilators tagad var izpildīt tipa pareizību - piemēram, sarakstu varētu saglabāt Dubultā tikai vērtības. Šī izpilde novērš nepieciešamību pēc (Dubultā) cast.

Vispārīgu veidu atklāšana

A vispārējs tips ir klase vai saskarne, kas ievada parametru tipu kopu, izmantojot a formālā tipa parametru saraksts, kas ir komatu atdalīts tipa parametru nosaukumu saraksts starp leņķa iekavu pāri. Vispārējie veidi atbilst šādai sintaksei:

klasē identifikators<formalTypeParameterList> {// klases ķermeņa} saskarne identifikators<formalTypeParameterList> {// saskarnes pamatteksts}

Java kolekciju ietvars piedāvā daudzus vispārīgu tipu piemērus un to parametru sarakstus (un es uz tiem atsaucos šajā rakstā). Piemēram, java.util.Set ir vispārējs veids, ir tā oficiālais tipu parametru saraksts un E ir saraksta vienīgā tipa parametrs. Vēl viens piemērs irjava.util.Karte.

Java tipa parametru nosaukšanas kārtība

Java programmēšanas konvencija nosaka, ka parametru nosaukumos jābūt atsevišķiem lielajiem burtiem, piemēram, E elementam, K par atslēgu, V par vērtību un T tipam. Ja iespējams, izvairieties lietot bezjēdzīgu vārdu, piemēram, Pjava.util.List nozīmē elementu sarakstu, bet ko jūs varētu domāt ar Saraksts

A parametru tips ir vispārēja tipa gadījums, kurā vispārējā tipa tipa parametri tiek aizstāti ar faktiskā tipa argumenti (tipa nosaukumi). Piemēram, Iestatiet ir parametrizēts tips, kur Stīga ir faktiskais tipa arguments, kas aizstāj tipa parametru E.

Java valoda atbalsta šāda veida faktiskos tipa argumentus:

  • Betona tips: Klases vai cita atsauces tipa nosaukums tiek nodots tipa parametram. Piemēram, Saraksts, Dzīvnieks tiek nodota E.
  • Betona parametru tips: Parametra tipa nosaukums tiek nodots tipa parametram. Piemēram, Iestatiet, Saraksts tiek nodota E.
  • Masīva tips: Masīvs tiek nodots tipa parametram. Piemēram, Karte, Stīga tiek nodota K un Virkne [] tiek nodota V.
  • Tips parametrs: Tipa parametrs tiek nodots tipa parametram. Piemēram, klase Konteiners {Komplekta elementi; }, E tiek nodota E.
  • Aizstājējzīme: Jautājuma zīme (?) tiek nodota tipa parametram. Piemēram, Klase, ? tiek nodota T.

Katrs vispārīgais veids nozīmē a esamību neapstrādāts veids, kas ir vispārējs tips bez formāla tipa parametru saraksta. Piemēram, Klase ir neapstrādāts veids Klase. Atšķirībā no vispārīgiem tipiem neapstrādātus veidus var izmantot ar jebkura veida objektiem.

Vispārējo tipu deklarēšana un izmantošana Java

Deklarējot vispārīgu tipu, ir jānorāda oficiāla tipa parametru saraksts un piekļuve šiem tipa parametriem visā tā ieviešanas laikā. Vispārējā tipa izmantošana nozīmē faktiskā tipa argumentu nodošanu tā tipa parametriem, kad tiek parādīts vispārīgais tips. Skatīt 1. sarakstu.

1. saraksts:GenDemo.java (1. versija)

klases Konteinera {privātie E [] elementi; privāts int indekss; Konteiners (int izmērs) {elements = (E []) jauns Objekts [izmērs]; indekss = 0; } void add (E elements) {elements [index ++] = elements; } E get (int indekss) {return elementi [indekss]; } int lielums () {atgriešanās indekss; }} public class GenDemo {public static void main (String [] args) {Container con = new Container (5); con.add ("ziemeļi"); con.add ("dienvidi"); con.add ("Austrumi"); con.add ("Rietumi"); par (int i = 0; i <con.size (); i ++) System.out.println (con.get (i)); }}

1. saraksts parāda vispārīga tipa deklarēšanu un lietošanu vienkārša konteinera veida kontekstā, kurā tiek glabāti atbilstoša argumenta tipa objekti. Lai kods būtu vienkāršs, esmu izlaidis kļūdu pārbaudi.

The Konteiners klase pasludina sevi par sugas tipu, norādot formālā tipa parametru saraksts. Tips parametrs E tiek izmantots, lai identificētu saglabāto elementu tipu, elementu, kas jāpievieno iekšējam masīvam, un atgriešanas veidu, izgūstot elementu.

The Konteiners (int izmērs) konstruktors izveido masīvu caur elementi = (E []) jauns Objekts [izmērs];. Ja jūs domājat, kāpēc es nenorādīju elementi = jauns E [izmērs];, iemesls ir tas, ka tas nav iespējams. To darot, varētu rasties ClassCastException.

Sastādīt 1. sarakstu (javac GenDemo.java). The (E []) cast liek kompilatoram izdot brīdinājumu par to, ka cast netiek pārbaudīts. Tas iezīmē iespēju, ka pazemināšana no Objekts [] uz E [] var pārkāpt tipa drošību, jo Objekts [] var uzglabāt jebkura veida objektus.

Tomēr ņemiet vērā, ka šajā piemērā nav iespējams pārkāpt tipa drošību. Vienkārši nav iespējams uzglabātE objekts iekšējā masīvā. Pielikums Konteiners (int izmērs) konstruktors ar @SuppressWarnings ("nav pārbaudīts") nomāktu šo brīdinājuma ziņojumu.

Izpildīt java GenDemo lai palaistu šo lietojumprogrammu. Jums jāievēro šāda izeja:

ziemeļi Dienvidi Austrumi Rietumi

Ierobežojošā tipa parametri Java

The E iekšā Iestatiet ir piemērs neierobežota tipa parametrs jo jūs varat nodot jebkuram faktiskā tipa argumentam E. Piemēram, jūs varat norādīt Iestatiet, Iestatietvai Iestatiet.

Dažreiz vēlaties ierobežot faktiskā tipa argumentu tipus, kurus var nodot tipa parametram. Piemēram, varbūt vēlaties ierobežot tipa parametru, lai tas tiktu pieņemts tikai Darbinieks un tās apakšklases.

Varat ierobežot tipa parametru, norādot augšējā robeža, kas ir tips, kas kalpo kā augšējā robeža tipiem, kurus var nodot kā faktiskos tipa argumentus. Norādiet augšējo robežu, izmantojot rezervēto vārdu pagarina seko augšējās robežas tipa nosaukums.

Piemēram, klases Darbinieki ierobežo tipus, kuriem var nodot Darbinieki uz Darbinieks vai apakšklase (piem., Grāmatvede). Norādot jaunie darbinieki būtu likumīgi, turpretī jaunie darbinieki būtu nelikumīgi.

Tipa parametram var piešķirt vairākas augšējās robežas. Tomēr pirmajai saistībai vienmēr jābūt klasei, un papildu robežām vienmēr jābūt saskarnēm. Katru saiti no priekšgājēja atdala ar zīmi (&). Pārbaudiet 2. sarakstu.

2. saraksts: GenDemo.java (2. versija)

importēt java.math.BigDecimal; importēt java.util.Arrays; abstraktā klase Darbinieks {private BigDecimal hourlySalary; privāts virknes nosaukums; Darbinieks (virknes nosaukums, BigDecimal hourlySalary) {this.name = vārds; this.hourlySalary = stundas alga; } public BigDecimal getHourlySalary () {return hourlySalary; } public String getName () {atgriešanās nosaukums; } public String toString () {return name + ":" + hourlySalary.toString (); }} klase Grāmatvedis paplašina Darbinieku ieviešanas iespējas Salīdzināms {Grāmatvedis (virknes nosaukums, BigDecimal hourlySalary) {super (vārds, hourlySalary); } public int salīdzinātTo (grāmatvedis acct) {atgūt getHourlySalary (). salīdzinātTo (acct.getHourlySalary ()); }} klases Šķirotie darbinieki {privātie E [] darbinieki; privāts int indekss; @SuppressWarnings ("nepārbaudīts") SortedEmployees (int size) {darbinieki = (E []) jauns darbinieks [izmērs]; int indekss = 0; } void add (E emp) {darbinieki [indekss ++] = emp; Masīvi.kārtot (darbinieki, 0, indekss); } E get (int indekss) {atgriežamie darbinieki [indekss]; } int lielums () {atgriešanās indekss; }} public class GenDemo {public static void main (String [] args) {SortedEmployees se = new SortedEmployees (10); se.add (jauns grāmatvedis ("John Doe", jauns BigDecimal ("35.40"))); se.add (jauns grāmatvedis ("George Smith", jauns BigDecimal ("15.20"))); se.add (jauns grāmatvedis ("Jane Jones", jauns BigDecimal ("25.60"))); par (int i = 0; i <se.size (); i ++) System.out.println (se.get (i)); }}

2. saraksts Darbinieks klase abstraktē darbinieka jēdzienu, kurš saņem stundas algu. Šī klase ir apakšklasē Grāmatvede, kas arī īsteno Salīdzināms lai to norādītu GrāmatvedeS var salīdzināt pēc to dabiskās kārtības, kas šajā piemērā gadās būt stundas alga.

The java.lang.Salīdzināms interfeiss tiek deklarēts kā vispārējs tips ar nosauktu viena tipa parametru T. Šī saskarne nodrošina int salīdzinātTo (T o) metode, kas pašreizējo objektu salīdzina ar argumentu (tipa T), atgriežot negatīvu veselu skaitli, nulli vai pozitīvu veselu skaitli, jo šis objekts ir mazāks, vienāds ar vai lielāks par norādīto objektu.

The KārtotiDarbinieki klase ļauj jums uzglabāt Darbinieks apakšklases gadījumi, kas tiek ieviesti Salīdzināms iekšējā masīvā. Šis masīvs ir sakārtots (izmantojot java.util.Arrays klases void sort (Object [] a, int fromIndex, int toIndex) klases metode) stundas algas pieaugošā secībā pēc Darbinieks tiek pievienota apakšklases instance.

Apkopot 2. sarakstu (javac GenDemo.java) un palaidiet lietojumprogrammu (java GenDemo). Jums jāievēro šāda izeja:

Džordžs Smits: 15.20 Džeina Džonsa: 25.60 Džons Doe: 35.40

Zemākās robežas un vispārējā tipa parametri

Vispārējā tipa parametram nevar norādīt zemāko robežu. Lai saprastu, kāpēc es iesaku izlasīt Angelika Langer bieži uzdotos jautājumus par Java Generics par zemāko robežu tēmu, kas, viņasprāt, “būtu mulsinoši un nebūtu īpaši noderīga”.

Ņemot vērā aizstājējzīmes

Pieņemsim, ka vēlaties izdrukāt objektu sarakstu neatkarīgi no tā, vai šie objekti ir virknes, darbinieki, formas vai kāds cits veids. Jūsu pirmais mēģinājums varētu izskatīties kā parādīts 3. sarakstā.

3. saraksts: GenDemo.java (3. versija)

importēt java.util.ArrayList; importēt java.util.Iterator; importēt java.util.List; public class GenDemo {public static void main (String [] args) {Saraksts norādes = new ArrayList (); norādes.pievienot ("ziemeļi"); norādes.add ("dienvidi"); norādes.add ("austrumi"); norādes.add ("rietumi"); printList (norādes); Sarakstu vērtējumi = new ArrayList (); pakāpes.pievienot (jauns vesels skaitlis (98)); pakāpes.pievienot (jauns vesels skaitlis (63)); pakāpes.pievienot (jauns vesels skaitlis (87)); printList (pakāpes); } static void printList (Sarakstu saraksts) {Iterator iter = list.iterator (); while (iter.hasNext ()) System.out.println (iter.next ()); }}

Šķiet loģiski, ka virkņu saraksts vai veselu skaitļu saraksts ir objektu saraksta apakštips, tomēr kompilators sūdzas, mēģinot sastādīt šo sarakstu. Konkrēti, tas jums saka, ka virkņu sarakstu nevar pārveidot par objektu sarakstu un līdzīgi kā veselu skaitļu sarakstu.

Saņemtais kļūdas ziņojums ir saistīts ar vispārīgo pamatnoteikumu:

Copyright lv.verticalshadows.com 2021