Programiranje

Kako uporabiti generične izdelke Java, da se izognemo ClassCastExceptions

Java 5 je v jezik Java prinesel generike. V tem članku vam predstavim generike in razpravljam o generičnih vrstah, generičnih metodah, generikih in sklepanju na tipe, generičnih polemikah ter generikih in onesnaževanju kupa.

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

Kaj so generiki?

Generiki so zbirka sorodnih jezikovnih lastnosti, ki omogočajo, da tipi ali metode delujejo na objektih različnih vrst, hkrati pa zagotavljajo varnost tipa prevajalskega časa. Generične funkcije obravnavajo problem java.lang.ClassCastExceptionvrženi med izvajanjem, ki so rezultat kode, ki ni varna za tip (tj. predvajanje predmetov iz njihovih trenutnih tipov v nezdružljive vrste).

Generiki in ogrodje zbirk Java

Generiki se pogosto uporabljajo v okviru Java Collections Framework (uradno predstavljeni v prihodnosti Java 101 članki), vendar zanjo niso izključni. Generiki se uporabljajo tudi v drugih delih Javine knjižnice standardnih razredov, vključno z java.lang.Class, java.lang.Primerljivo, java.lang.ThreadLocal, in java.lang.ref.WeakReference.

Razmislite o naslednjem fragmentu kode, ki dokazuje pomanjkanje varnosti tipa (v okviru okvira Java Collections Framework java.util.LinkedList class), ki je bila pogosta v kodi Java pred uvedbo generičnih zdravil:

Seznam doubleList = nov LinkedList (); doubleList.add (novo Double (3.5)); Double d = (Double) doubleList.iterator (). Next ();

Čeprav je cilj zgornjega programa le shranjevanje java.lang.Dvojnik predmetov na seznamu, nič ne preprečuje shranjevanja drugih vrst predmetov. Lahko na primer določite doubleList.add ("Pozdravljeni"); da dodate a java.lang.String predmet. Pri shranjevanju druge vrste predmeta, končne vrstice (Dvojno) vzroki operaterja zasedbe ClassCastException biti vržen, ko se sooči zDvojno predmet.

Ker tega pomanjkanja varnosti tipa zaznamo šele med izvajanjem, se razvijalec morda ne zaveda težave in prepusti odjemalcu (namesto prevajalniku), da odkrije. Generiki pomagajo prevajalniku opozoriti razvijalca na težavo shranjevanja predmeta z ne-Dvojno vnesite na seznam tako, da razvijalcu dovolite, da ga označi kot samo vsebuje Dvojno predmetov. Ta pomoč je prikazana spodaj:

Seznam doubleList = nov LinkedList (); doubleList.add (novo Double (3.5)); Double d = doubleList.iterator (). Next ();

Seznam zdaj se glasi "Seznam od Dvojno.” Seznam je generični vmesnik, izražen kot Seznam, kar traja Dvojno argument tipa, ki je prav tako določen pri ustvarjanju dejanskega predmeta. Prevajalnik lahko zdaj uveljavi pravilnost tipa pri dodajanju predmeta na seznam - seznam lahko na primer shrani Dvojno samo vrednosti. To izvrševanje odpravlja potrebo po (Dvojno) igralska zasedba.

Odkrivanje generičnih vrst

A generični tip je razred ali vmesnik, ki uvede nabor parametriziranih tipov prek a seznam parametrov formalnega tipa, ki je ločen z vejicami seznam imen parametrov tipa med dvema kotnima oklepajema. Splošni tipi se držijo naslednje skladnje:

razred identifikator<formalTypeParameterList> {// class body} vmesnik identifikator<formalTypeParameterList> {// telo vmesnika}

Okvir Java Collections Framework ponuja veliko primerov generičnih tipov in njihovih seznamov parametrov (in nanje se sklicujem v tem članku). Na primer, java.util.Set je generična vrsta, je njegov formalni seznam parametrov tipa in E je samotni tip parametra na seznamu. Drug primer jejava.util.Map.

Dogovor o poimenovanju parametrov tipa Java

Konvencija o programiranju Java narekuje, da so imena parametrov tipa ene velike črke, na primer E za element, K za ključ, V za vrednost in T za tip. Če je mogoče, se izogibajte uporabi nesmiselnega imena, kot je Pjava.util.List pomeni seznam elementov, toda kaj bi lahko mislili z Seznam

A parametriziran tip je primerek generičnega tipa, pri katerem so parametri tipa generičnega tipa nadomeščeni z dejanski argumenti tipa (imena vrst). Na primer, Nastavite je parametriziran tip, kjer Vrvica je dejanski argument tipa, ki nadomešča parameter tipa E.

Jezik Java podpira naslednje vrste dejanskih argumentov tipa:

  • Vrsta betona: Ime razreda ali drugega referenčnega tipa se prenese parametru tipa. Na primer, v Seznam, Žival je posredovano E.
  • Konkretni parametrizirani tip: Parametrizirano ime tipa se posreduje parametru tipa. Na primer, v Nastavite, Seznam je posredovano E.
  • Vrsta matrike: Matrika se posreduje parametru tipa. Na primer, v Zemljevid, Vrvica je posredovana K in Vrvica[] je posredovano V.
  • Parameter tipa: Parameter tipa se posreduje parametru tipa. Na primer, v class Container {Set elements; }, E je posredovano E.
  • Nadomestni znak: Vprašaj (?) se posreduje parametru tipa. Na primer, v Razred, ? je posredovano T.

Vsaka generična vrsta pomeni obstoj a surov tip, ki je generični tip brez formalnega seznama parametrov tipa. Na primer, Razred je surova vrsta za Razred. V nasprotju s splošnimi vrstami se surove vrste lahko uporabljajo s kakršnimi koli predmeti.

Izjava in uporaba generičnih vrst v Javi

Razglasitev generičnega tipa vključuje določitev formalnega seznama parametrov tipa in dostop do teh parametrov tipa skozi njegovo izvajanje. Uporaba generičnega tipa vključuje posredovanje dejanskih argumentov tipa njegovim parametrom tipa, ko ustvari generični tip. Glej seznam 1.

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

class Container {private E [] elementi; zasebni indeks int; Vsebnik (int size) {elements = (E []) new Object [size]; indeks = 0; } void add (E element) {elements [index ++] = element; } E get (int index) {return elementi [indeks]; } int size () {indeks vrnitve; }} javni razred GenDemo {public static void main (String [] args) {Container con = new Container (5); con.add ("sever"); con.add ("Jug"); con.add ("vzhod"); con.add ("Zahod"); for (int i = 0; i <con.size (); i ++) System.out.println (con.get (i)); }}

Seznam 1 prikazuje generično deklaracijo in uporabo v kontekstu preprostega tipa vsebnika, ki hrani predmete ustrezne vrste argumenta. Da bo koda preprosta, sem izpustil preverjanje napak.

The Zabojnik razred razglasi, da je generičen tip z določitvijo seznam parametrov formalnega tipa. Vnesite parameter E se uporablja za identifikacijo vrste shranjenih elementov, elementa, ki ga je treba dodati notranjemu polju, in vrste vrnitve pri pridobivanju elementa.

The Posoda (int velikost) konstruktor ustvari matriko prek elementi = (E []) nov objekt [velikost];. Če se sprašujete, zakaj nisem navedel elementi = novi E [velikost];, razlog je, da to ni mogoče. S tem bi lahko prišlo do ClassCastException.

Sestavi seznam 1 (javac GenDemo.java). The (E []) cast povzroči, da prevajalnik prikaže opozorilo o tem, da oddaja ni potrjena. Označuje možnost, da spuščanje iz Predmet [] do E [] lahko krši varnost tipa, ker Predmet [] lahko shrani katero koli vrsto predmeta.

Upoštevajte pa, da v tem primeru ni mogoče kršiti varnosti tipa. Preprosto ni mogoče shranitiE objekt v notranjem polju. Predpona Posoda (int velikost) konstruktor z @SuppressWarnings ("nepreverjeno") bi potisnil to opozorilno sporočilo.

Izvedite java GenDemo za zagon te aplikacije. Upoštevati morate naslednje rezultate:

sever jug ​​vzhod zahod

Omejevalni parametri tipa v Javi

The E v Nastavite je primer neomejeni tip parametra ker lahko posredujete kateri koli dejanski argument tipa E. Lahko na primer določite Nastavite, Nastavite, ali Nastavite.

Včasih boste želeli omejiti vrste dejanskih argumentov tipa, ki jih lahko posredujete parametru tipa. Na primer, morda želite omejiti, da parameter tipa sprejema samo Zaposleni in njegovih podrazredih.

Parameter tipa lahko omejite tako, da podate Zgornja meja, ki je tip, ki služi kot zgornja meja za tipe, ki jih je mogoče prenesti kot dejanske argumente tipa. Z rezervirano besedo določite zgornjo mejo podaljša čemur sledi ime tipa zgornje meje.

Na primer, razred Zaposleni omejuje vrste, na katere je mogoče prenesti Zaposleni do Zaposleni ali podrazred (npr. Računovodja). Določanje novi zaposleni bi bilo zakonito, medtem ko novi zaposleni bi bilo nezakonito.

Parametru tipa lahko dodelite več kot eno zgornjo mejo. Vendar mora biti prva vezava vedno razred, dodatne meje pa vedno vmesniki. Vsaka vezava je od predhodnika ločena z znakom (&). Oglejte si seznam 2.

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

uvoz java.math.BigDecimal; uvoz java.util.Arrays; abstraktni tečaj Zaposleni {private BigDecimal hourlySalary; ime zasebnega niza; Zaposleni (ime niza, BigDecimal hourlySalary) {this.name = name; this.hourlySalary = urna plača; } public BigDecimal getHourlySalary () {return hourlySalary; } javni niz getName () {return ime; } javni String toString () {return ime + ":" + hourlySalary.toString (); }} class Accountant extends Zaposleni implementira Comparable {Accountant (String name, BigDecimal hourlySalary) {super (name, hourlySalary); } public int compareTo (Accountant acct) {return getHourlySalary (). compareTo (acct.getHourlySalary ()); }} razred SortedE Employees {zasebni uslužbenci E []; zasebni indeks int; @SuppressWarnings ("nepreverjeno") SortedE Employees (int size) {zaposlenih = (E []) new Employee [size]; indeks int = 0; } void add (E emp) {zaposlenih [indeks ++] = emp; Arrays.sort (zaposleni, 0, indeks); } E get (int index) {vrnitev zaposlenih [indeks]; } int size () {indeks vrnitve; }} javni razred GenDemo {javna statična void main (String [] args) {SortedEfficiees se = new SortedEfficiees (10); se.add (novi računovodja ("John Doe", novi BigDecimal ("35,40"))); se.add (novi računovodja ("George Smith", novi BigDecimal ("15.20"))); se.add (novi računovodja ("Jane Jones", novi BigDecimal ("25.60"))); for (int i = 0; i <se.size (); i ++) System.out.println (se.get (i)); }}

Seznam 2 Zaposleni razred povzema koncept zaposlenega, ki prejema urno plačo. Ta razred je podrazvrščen z Računovodja, ki tudi izvaja Primerljivo da to označi Računovodjas lahko primerjamo glede na njihov naravni red, ki je v tem primeru urna plača.

The java.lang.Primerljivo vmesnik je razglašen kot generični tip z imenom enega samega parametra tipa T. Ta vmesnik ponuja int compareTo (T o) metoda, ki primerja trenutni objekt z argumentom (tipa T), vrne negativno celo število, nič ali pozitivno celo število, saj je ta objekt manjši od, enak ali večji od določenega predmeta.

The SortiranoZaposleni razred vam omogoča shranjevanje Zaposleni primerki podrazreda, ki se izvajajo Primerljivo v notranjem polju. Ta matrika je razvrščena (prek java.util.Arrays razreda void sort (Object [] a, int fromIndex, int toIndex) razredna metoda) v naraščajočem vrstnem redu urne postavke po Zaposleni doda se primerek podrazreda.

Sestavi seznam 2 (javac GenDemo.java) in zaženite aplikacijo (java GenDemo). Upoštevati morate naslednje rezultate:

George Smith: 15.20 Jane Jones: 25.60 John Doe: 35.40

Spodnje meje in splošni parametri tipa

Za parameter generičnega tipa ne morete podati spodnje meje. Da bi razumeli, zakaj priporočam, da preberete pogosta vprašanja o Javni generiki Angelike Langer na temo spodnjih meja, za katere pravi, da bi bile "zmedene in ne posebej koristne".

Glede na nadomestne znake

Recimo, da želite natisniti seznam predmetov, ne glede na to, ali so ti predmeti nizi, zaposleni, oblike ali druge vrste. Vaš prvi poskus je lahko videti tako, kot je prikazano na seznamu 3.

Seznam 3: GenDemo.java (različica 3)

uvoz java.util.ArrayList; uvoz java.util.Iterator; uvoz java.util.List; javni razred GenDemo {public static void main (String [] args) {Seznam navodil = new ArrayList (); direction.add ("sever"); direction.add ("jug"); direction.add ("vzhod"); direction.add ("zahod"); printList (navodila); Seznam ocen = novo ArrayList (); grade.add (novo celo število (98)); grade.add (novo celo število (63)); grade.add (novo celo število (87)); printList (ocene); } static void printList (seznam seznam) {Iterator iter = list.iterator (); while (iter.hasNext ()) System.out.println (iter.next ()); }}

Zdi se logično, da je seznam nizov ali seznam celih števil podvrsta seznama predmetov, vendar se prevajalnik pritožuje, ko poskušate sestaviti ta seznam. Natančneje, pove vam, da seznama nizov ni mogoče pretvoriti v seznam predmetov in podobno za seznam celih števil.

Sporočilo o napaki, ki ste ga prejeli, je povezano s temeljnim pravilom generikov:

Copyright sl.verticalshadows.com 2022