En generisk type er en generisk klasse eller et grensesnitt som er parameterisert over typer. Følgende Box-klasse vil bli endret for å demonstrere konseptet.
En enkel Box-klasse
Begynn med å undersøke en ikke-generisk Box-klasse som fungerer på objekter av hvilken som helst type. Det trenger bare å tilby to metoder: sett, som legger til et objekt i boksen, og få, som henter det:
Siden metodene godtar eller returnerer et objekt, er du fri til å sende inn hva du vil , forutsatt at det ikke er en av de primitive typene. Det er ingen måte å verifisere hvordan klassen brukes på kompileringstidspunktet. En del av koden kan plassere et heltall i boksen og forvente å få heltall ut av det, mens en annen del av koden feilaktig kan passere i en streng, noe som resulterer i en kjøretidsfeil.
En generisk versjon av Box Class
En generisk klasse er definert med følgende format:
class name<T1, T2, ..., Tn> { /* ... */ }
For å oppdatere Box-klasse for å bruke generikk, du oppretter en generisk typedeklarasjon ved å endre koden «public class Box» til «public class Box < T > «. Dette introduserer typevariabelen, T, som kan brukes hvor som helst i klassen.
Med denne endringen blir Box-klassen:
Som du kan se, er alle forekomster av Object erstattet av T. En typevariabel kan være hvilken som helst ikke-primitiv type du angir: hvilken som helst klassetype, hvilken som helst grensesnitttype, hvilken som helst matritype eller til og med en annen type variabel.
Den samme teknikken kan brukes til å generiske grensesnitt.
Type Parameter Navngivningskonvensjoner
Etter konvensjon er typeparameternavn enkelt, store bokstaver. Dette står i skarp kontrast til variabelnavngivningskonvensjonene du allerede vet om, og med god grunn: Uten denne konvensjonen ville det være vanskelig å se forskjellen mellom en typevariabel og et vanlig klasse- eller grensesnittnavn.
De mest brukte typeparameternavnene er:
- E – Element (brukt mye av Java Collections Framework)
- K – Nøkkel
- N – Antall
- T – Type
- V – Verdi
- S, U, V etc. – 2., 3., 4. type
Du vil se disse navnene som brukes i Java SE API og resten av denne leksjonen.
Påkalle og installere en generisk type
For å referere til generisk Box-klasse innenfra koden din, må du utføre en generisk påkalling som erstatter T med en viss konkret verdi, for eksempel Heltall:
Box<Integer> integerBox;
Du kan tenke på en generisk innkalling som ligner på en vanlig metodeinnkallelse, men i stedet for å gi et argument til am ethod, sender du et typeargument – Heltall i dette tilfellet – til selve Box-klassen.
Som enhver annen variabelerklæring, oppretter ikke denne koden faktisk et nytt Box-objekt. Den erklærer ganske enkelt at integerBox vil ha en referanse til en «Box of Integer», slik leses Box < Heltall >.
En påkallelse av en generisk type er vanligvis kjent som en parameterisert type.
For å instantiere denne klassen, bruk det nye nøkkelordet, som vanlig, men plasser < Heltall > mellom klassenavnet og parentesen:
Box<Integer> integerBox = new Box<Integer>();
Diamanten
I Java SE 7 og nyere kan du erstatte typeargumentene som kreves for å påkalle konstruktøren til en generisk klasse med et tomt sett med typeargumenter (< >) så lenge kompilatoren kan bestemme, eller utlede, typeargumentene fra konteksten. Dette paret av vinkelfester, < >, kalles uformelt diamanten. For eksempel kan du opprette en forekomst av Box < Heltall > med følgende utsagn:
Box<Integer> integerBox = new Box<>();
For mer informasjon om diamantnotasjon og typen inferens, se Type inferens.
Flere typeparametere
Som nevnt tidligere, en generisk klasse kan ha flere typeparametere.For eksempel den generiske OrderedPair-klassen, som implementerer det generiske Pair-grensesnittet:
Følgende utsagn skaper to instantiations av OrderedPair-klassen:
Koden, ny OrderedPair < Streng, heltall >, instantierer K som en streng og V som et heltall. Derfor er parametertypene til OrderedPair’s konstruktør henholdsvis String og Integer. På grunn av autoboksing er det gyldig å sende en streng og en int til klassen.
Som nevnt i The Diamond, fordi en Java-kompilator kan utlede K- og V-typene fra erklæringen OrderedPair < Streng, heltall >, disse utsagnene kan forkortes ved hjelp av diamantnotasjon:
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");
For å opprette et generisk grensesnitt, følg de samme konvensjonene som for å lage en generisk klasse.
Parameteriserte typer
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));