„Java 5“ atvedė generinius vaistus į „Java“ kalbą. Šiame straipsnyje aš supažindinu jus su generiniais vaistais ir aptariu generinius tipus, bendrinius metodus, generinius ir tipų išvada, generikų ginčus, generinius vaistus ir krūvos taršą.
atsisiųsti Gauti kodą Atsisiųskite šios „Java 101“ mokymo programos pavyzdžių šaltinio kodą. Sukūrė Jeffas Friesenas, skirtas „JavaWorld“.Kas yra generiniai vaistai?
Generikai yra susijusių kalbų ypatybių rinkinys, leidžiantis tipams ar metodams valdyti įvairių tipų objektus, tuo pačiu užtikrinant kompiliavimo laiko saugumą. Bendrosios savybės sprendžia java.lang.ClassCastException
s metami vykdymo metu, o tai yra kodo, kuris nėra saugus tipas, rezultatas (t. y. objektų liejimas iš dabartinių tipų į nesuderinamus).
„Generics“ ir „Java Collections Framework“
Generics yra plačiai naudojami „Java Collections Framework“ (oficialiai pristatomi ateityje „Java 101“ straipsniai), tačiau jie nėra jai išskirtiniai. Generikai taip pat naudojami kitose „Java“ standartinių klasių bibliotekos dalyse, įskaitant java.lang.Klasė
, java.lang.Palyginamas
, java.lang.ThreadLocal
ir java.lang.ref.WeakReference
.
Apsvarstykite šį kodo fragmentą, kuris rodo tipo saugumo trūkumą („Java Collections Framework“ kontekste java.util.LinkedList
klasė), kuris buvo įprastas „Java“ kode prieš įvedant generinius:
Sąrašas doubleList = new LinkedList (); doubleList.add (naujas Double (3.5)); Dvigubas d = (Double) doubleList.iterator (). Kitas ();
Nors pirmiau minėtos programos tikslas yra tik saugoti java.lang.Dvigubai
sąrašą, niekas netrukdo saugoti kitų rūšių objektus. Pavyzdžiui, galite nurodyti doubleList.add („Labas“);
pridėti a java.lang.Stringas
objektas. Tačiau saugant kitos rūšies objektą, paskutinę eilutę (Dvivietis)
dauguma operatoriaus sukelia „ClassCastException“
išmesti susidūrus su neDvigubai
objektas.
Kadangi šis tipo saugos trūkumas nenustatomas iki vykdymo laiko, kūrėjas gali nežinoti problemos, palikdamas ją klientui (o ne kompiliatoriui) atrasti. „Generics“ padeda kompiliatoriui įspėti kūrėją apie objekto saugojimo su neDvigubai
įveskite į sąrašą, leisdami kūrėjui pažymėti, kad sąraše yra tik Dvigubai
objektai. Ši pagalba parodyta žemiau:
Sąrašas doubleList = new LinkedList (); doubleList.add (naujas Double (3.5)); Dvigubas d = doubleList.iterator (). Kitas ();
Sąrašas
dabar skaito „Sąrašas
apie Dvigubai
.” Sąrašas
yra bendroji sąsaja, išreikšta kaip Sąrašas
, tam reikia a Dvigubai
tipo argumentas, kuris taip pat nurodomas kuriant faktinį objektą. Kompiliatorius dabar gali įtvirtinti tipo teisingumą, kai įtraukia objektą į sąrašą, pavyzdžiui, sąrašą galima išsaugoti Dvigubai
tik vertybės. Šis vykdymas pašalina poreikį (Dvivietis)
mesti.
Atrasti bendrinius tipus
A bendrinis tipas yra klasė arba sąsaja, įvedanti parametrų tipų rinkinį per formalaus tipo parametrų sąrašas, kuris yra kableliais atskirtas tipų parametrų pavadinimų sąrašas tarp kampinių skliaustų poros. Bendrieji tipai atitinka šią sintaksę:
klasė identifikatorius<formalTypeParameterList> {// class body} sąsaja identifikatorius<formalTypeParameterList> {// sąsajos turinys}
„Java Collections Framework“ pateikia daug bendrų tipų ir jų parametrų sąrašų pavyzdžių (ir aš juos remiuosi šiame straipsnyje). Pavyzdžiui, java.util.Rinkinys
yra bendrinis tipas, yra jo oficialus tipo parametrų sąrašas ir
E
yra sąrašo pavienio tipo parametras. Kitas pavyzdys yrajava.util.Žemėlapis
.
„Java“ tipo parametrų pavadinimo tvarka
„Java“ programavimo sutartis nurodo, kad tipo parametrų pavadinimai turi būti vienos didžiosios raidės, pvz A parametruojamas tipas yra bendro tipo egzempliorius, kuriame pakeičiami bendro tipo tipo parametrai faktinio tipo argumentai (tipų pavadinimai). Pavyzdžiui, „Java“ kalba palaiko šiuos faktinio tipo argumentus: Kiekvienas bendrinis tipas reiškia a egzistavimą žalio tipo, kuris yra bendrasis tipas be oficialaus tipo parametrų sąrašo. Pavyzdžiui, Deklaruojant bendrąjį tipą, reikia nurodyti oficialų tipo parametrų sąrašą ir pasiekti šiuos tipo parametrus jo įgyvendinimo metu. Naudojant bendrąjį tipą, tikrojo tipo argumentai perduodami jo tipo parametrams, kai nustatomas bendrasis tipas. Žr. 1 sąrašą. 1 sąrašas parodo bendro tipo deklaravimą ir naudojimą paprasto konteinerio tipo, kuriame saugomi atitinkamo argumento tipo objektai, kontekste. Kad kodas būtų paprastas, praleidau klaidų tikrinimą. Sudaryti 1 sąrašą ( Tačiau atkreipkite dėmesį, kad šiame pavyzdyje jokiu būdu negalima pažeisti tipo saugos. Tiesiog neįmanoma laikyti ne Vykdyti Kartais norėsite apriboti faktinio tipo argumentų tipus, kuriuos galima perduoti tipo parametrui. Pvz., Galbūt norite apriboti tipo parametrą, kad jis būtų priimtas tik Tipo parametrą galite apriboti nurodydami viršutinė riba, kuris yra tipas, kuris naudojamas kaip viršutinė riba tipams, kuriuos galima perduoti kaip faktinius tipo argumentus. Nurodykite viršutinę ribą naudodami rezervuotą žodį Pavyzdžiui, Tipo parametrui galite priskirti daugiau nei vieną viršutinę ribą. Tačiau pirmoji riba visada turi būti klasė, o papildomos ribos visada turi būti sąsajos. Kiekvieną įrišimą nuo pirmtako skiria ampersandas ( 2 sąrašas Sudaryti 2 sąrašą ( Negalite nurodyti apatinės ribos bendro tipo parametrui. Norėdami suprasti, kodėl aš rekomenduoju perskaityti Angelikos Langer „Java Generics“ DUK apie apatines ribas, kurie, jos teigimu, „būtų painūs ir ne itin naudingi“. Tarkime, kad norite atsispausdinti objektų sąrašą, neatsižvelgiant į tai, ar šie objektai yra eilutės, darbuotojai, formos ar kokio kito tipo. Pirmasis jūsų bandymas gali atrodyti taip, kaip parodyta 3 sąraše. Atrodo logiška, kad eilučių arba sveikųjų skaičių sąrašas yra objektų sąrašo potipis, tačiau kompiliatorius skundžiasi, kai bandote sudaryti šį sąrašą. Tiksliau sakant, jums sakoma, kad eilutės sąrašas negali būti paverstas objekto sąrašu ir panašiai kaip sveikų skaičių sąrašas. Gautas klaidos pranešimas yra susijęs su pagrindine generikų taisykle:E
elementui, K.
raktui, V
už vertę ir T
tipui. Jei įmanoma, venkite naudoti beprasmį pavadinimą, pvz P
— java.util.Sąrašas
reiškia elementų sąrašą, bet ką galėtumėte pasakyti Sąrašas
Nustatyti
yra parametruojamas tipas, kur Stygos
yra tikrasis tipo argumentas, pakeičiantis tipo parametrą E
.Sąrašas
, Gyvūnas
yra perduodama E
.Nustatyti
, Sąrašas
yra perduodama E
.Žemėlapis
, Stygos
yra perduodama K.
ir Stygos []
yra perduodama V
.klasės konteineris {Nustatyti elementus; }
, E
yra perduodama E
.?
) perduodamas tipo parametrui. Pavyzdžiui, Klasė
, ?
yra perduodama T
.Klasė
yra neapdorotas Klasė
. Skirtingai nuo bendrų tipų, neapdorotus tipus galima naudoti su bet kokio tipo objektais.Bendrų tipų deklaravimas ir naudojimas „Java“
1 sąrašas:
GenDemo.java
(1 versija)klasės „Container {private E []“ elementai; privatus int indeksas; Konteineris (int dydis) {elementai = (E []) naujas objektas [dydis]; indeksas = 0; } void add (E elementas) {elementai [rodyklė ++] = elementas; } E get (int index) {return elementai [rodyklė]; } int dydis () {grąžos indeksas; }} public class GenDemo {public static void main (String [] args) {Container con = new Container (5); con.add („Šiaurė“); con.add („Pietūs“); con.add („Rytai“); con.add („Vakarai“); for (int i = 0; i <con.size (); i ++) System.out.println (con.get (i)); }}
Konteineris
klasė pasiskelbia esanti bendro tipo, nurodydama formalaus tipo parametrų sąrašas. Tipo parametras
E
naudojamas identifikuoti saugomų elementų tipą, elementą, kurį reikia pridėti prie vidinio masyvo, ir grąžinimo tipą, kai gaunamas elementas.Konteineris (int dydis)
konstruktorius sukuria masyvą per elementai = (E []) naujas objektas [dydis];
. Jei įdomu, kodėl nenurodžiau elementai = naujas E [dydis];
, priežastis ta, kad tai neįmanoma. Tai padarius, gali atsirasti a „ClassCastException“
.javac GenDemo.java
). (E [])
„cast“ verčia kompiliatorių pateikti įspėjimą apie tai, kad aktoriai nėra pažymėti. Tai pažymi galimybę, kad žeminimas iš Objektas []
į E []
gali pažeisti tipo saugumą, nes Objektas []
gali saugoti bet kokio tipo objektus.E
objektas vidiniame masyve. Priešdėlis Konteineris (int dydis)
konstruktorius su @SuppressWarnings ("nepažymėta")
nuslopintų šį įspėjamąjį pranešimą.java GenDemo
paleisti šią programą. Turėtumėte stebėti šį rezultatą:Šiaurė, pietūs, rytai, vakarai
Apribojimo tipo parametrai „Java“
E
į Nustatyti
yra pavyzdys neriboto tipo parametras nes galite perduoti bet kokį faktinio tipo argumentą E
. Pavyzdžiui, galite nurodyti Nustatyti
, Nustatyti
arba Nustatyti
.Darbuotojas
ir jo poklasiai.tęsiasi
po kurio nurodomas viršutinės ribos tipo pavadinimas.klasės darbuotojai
apriboja tipus, kuriems galima perduoti Darbuotojai
į Darbuotojas
arba poklasis (pvz., Buhalterė
). Nurodant nauji darbuotojai
būtų teisėta, o nauji darbuotojai
būtų neteisėta.&
). Peržiūrėkite 2 sąrašą.2 sąrašas:
GenDemo.java
(2 versija)importuoti java.math.BigDecimal; importuoti java.util.Arrays; abstrakti klasė Darbuotojas {private BigDecimal hourlySalary; asmeninės eilutės pavadinimas; Darbuotojas (eilutės pavadinimas, „BigDecimal hourlySalary“) {this.name = vardas; this.hourlySalary = valandinis atlygis; } public BigDecimal getHourlySalary () {return hourlySalary; } public String getName () {grąžinimo vardas; } public String toString () {return name + ":" + hourlySalary.toString (); }} klasė Buhalteris praplečia Darbuotojų įrankius Palyginamieji {buhalteris (eilutės pavadinimas, BigDecimal hourlySalary) {super (vardas, hourlySalary); } public int CompareTo (Accountant acct) {return getHourlySalary (). CompareTo (acct.getHourlySalary ()); }} klasės Rūšiuoti darbuotojai
Darbuotojas
klasė apibendrina darbuotojo, gaunančio valandinį atlygį, sampratą. Ši klasė yra subklasė Buhalterė
, kuris taip pat įgyvendina Palyginamas
kad tai nurodytų Buhalterė
S galima palyginti pagal jų natūralią tvarką, kuri šiame pavyzdyje būna valandinis atlygis.java.lang.Palyginamas
sąsaja yra deklaruojama kaip bendrasis tipas su vieno tipo parametru, pavadintu T
. Ši sąsaja suteikia int palygintiTo (T o)
metodas, lyginantis esamą objektą su argumentu (tipo T
), grąžinant neigiamą sveiką skaičių, nulį arba teigiamą sveiką skaičių, nes šis objektas yra mažesnis, lygus arba didesnis už nurodytą objektą.RūšiuotiDarbuotojai
klasė leidžia jums laikyti Darbuotojas
poklasio egzemplioriai, kurie įgyvendinami Palyginamas
vidiniame masyve. Šis masyvas yra rūšiuojamas (per java.util.A arrays
klasės void sort (Object [] a, int fromIndex, int toIndex)
klasės metodas) didėjančia valandinio atlygio tvarka po Darbuotojas
pridedama poklasio egzempliorius.javac GenDemo.java
) ir paleiskite programą (java GenDemo
). Turėtumėte stebėti šį rezultatą:George'as Smithas: 15.20 Jane Jones: 25.60 John Doe: 35.40
Apatinės ribos ir bendro tipo parametrai
Atsižvelgiant į pakaitos simbolius
3 sąrašas:
GenDemo.java
(3 versija)importuoti java.util.ArrayList; importuoti java.util.Iterator; importuoti java.util.List; public class GenDemo {public static void main (String [] args) {Nurodyti nuorodas = new ArrayList (); kryptys.add ("šiaurė"); kryptys.add ("pietūs"); kryptys.add ("rytai"); kryptys.add ("vakarai"); printList (kryptys); Sąrašų sąrašas = naujas „ArrayList“ (); pažymiai.add (naujas sveikasis skaičius (98)); pažymiai.add (naujas sveikasis skaičius (63)); pažymiai.add (naujas sveikasis skaičius (87)); printList (pažymiai); } static void printList (Sąrašų sąrašas) {Iterator iter = list.iterator (); while (iter.hasNext ()) System.out.println (iter.next ()); }}