Programmering

Java 101: Det essensielle Java-språket inneholder tur, del 5

Forrige 1 2 Side 2 Side 2 av 2

Skriv inferens og generiske konstruktører for generiske og ikke-generiske klasser

Generiske og ikke-generiske klasser kan erklære generiske konstruktører der en konstruktør har en formell type parameterliste. For eksempel kan du erklære følgende generiske klasse med en generisk konstruktør:

 public class Box {public Box (T t) {// ...}} 

Denne erklæringen spesifiserer generisk klasse Eske med formell type parameter E. Den spesifiserer også en generisk konstruktør med formell typeparameter T. Du kan starte den generiske klassen og påkalle konstruktøren som følger:

 new Box ("Aggies") 

Dette uttrykket skaper en forekomst av Eske, passering Marmor til E. Også kompilatoren utleder String som Ts faktiske type argument fordi konstruktørens argument er en String gjenstand.

Pre-Java 7-kompilatorer utleder en generisk konstruktors faktiske typeargumenter på samme måte som en generisk metode. Imidlertid kan Java 7s kompilator utlede de faktiske typeargumentene til den generiske klassen som instantieres i en diamantoperatørkontekst. Tenk på følgende eksempel:

 Box box = new Box ("Aggies"); 

Samt å utlede typen Marmor for formell type parameter E av generisk klasse Eske, kompilatoren utleder typen String for formell type parameter T av denne generiske klassens konstruktør.

Prosjektmynt liten endring # 8: Forenklet påkallelse av varargs-metoden

Før Java 7 forsøkte hvert å påkalle varargs (variable argumenter, også kjent som variabel aritet) -metoden med en ikke-repeterbar varargs-type fikk kompilatoren til å sende ut en "usikker operasjon" -varsel. For å eliminere potensialet for mange lignende advarsler (en per anropsside), flyttet Java 7 advarselen fra anropssiden til metodedeklarasjonen.

Reifiable og non-reifiable typer

EN gjenvinnbar type avslører fullstendig typeinformasjon ved kjøretid. Eksempler inkluderer primitive typer, ikke-generiske typer, råtyper og påkallinger av ubundne jokertegn. I kontrast, a ikke-refifiserbar type har fjernet typeinformasjon ved kompilering etter type sletting, for å sikre binær kompatibilitet med Java-biblioteker og applikasjoner som ble opprettet før generiske. Eksempler inkluderer Sett og Sett. Fordi en ikke-refifiserbar type ikke er helt tilgjengelig under kjøretid, kan ikke JVM se forskjellen på Sett og Sett; ved kjøretid, bare den rå typen Sett er tilgjengelig.

Generiske metoder som inkluderer vararg-inngangsparametere kan forårsake haugforurensning, der en variabel av en parameterisert type refererer til et objekt som ikke er av den parameteriserte typen (for eksempel hvis en rå type har blitt blandet med en parameterisert type). Kompilatoren rapporterer en "ukontrollert advarsel" fordi riktigheten av en operasjon som involverer en parameterisert type (som en rollebesetning eller metodeanrop) ikke kan bekreftes.

Oppføring 13 viser haugforurensning i en ikke-vargsammenheng.

Oppføring 13. Demonstrasjon av haugforurensning i en ikke-vargsammenheng

 importere java.util.Iterator; importere java.util.Set; importere java.util.TreeSet; public class HeapPollutionDemo {public static void main (String [] args) {Set s = new TreeSet (); Sett ss = s; // ukontrollert advarsel s.add (nytt heltal (42)); // en annen ukontrollert advarsel Iterator iter = ss.iterator (); mens (iter.hasNext ()) {String str = iter.next (); // ClassCastException kastet System.out.println (str); }}} 

Variabel ss har parameterisert type Sett. Når java.util.Sett det er referert til av s er tildelt ss, genererer kompilatoren en ukontrollert advarsel. Det gjør det fordi kompilatoren ikke kan bestemme det s refererer til en Sett type (det gjør det ikke). Resultatet er haugforurensning. (Kompilatoren tillater at denne oppgaven bevarer bakoverkompatibilitet med eldre Java-versjoner som ikke støtter generisk. Videre skriver type sletting om Sett inn i Sett, som resulterer i en Sett blir tildelt en annen Sett.)

Kompilatoren genererer en andre ukontrollert advarsel på linjen som påkaller Setts legge til() metode. Det gjør det fordi det ikke kan avgjøre om det er variabelt s refererer til en Sett eller Sett type. Dette er nok en forurensningssituasjon. (Kompilatoren tillater denne metoden samtale fordi sletting transformeres Setts boolsk tilsetning (E e) metode til boolsk tilsetning (Objekt o), som kan legge til alle slags objekter i settet, inkludert java.lang. heltall undertype av java.lang.Objekt.)

Haugforurensning kan lett forekomme i en vargsammenheng. Tenk for eksempel på liste 14.

Oppføring 14. Demonstrasjon av haugforurensning i varargs sammenheng

 importere java.util.Arrays; importere java.util.List; public class UnsafeVarargsDemo {public static void main (String [] args) {unsafe (Arrays.asList ("A", "B", "C"), Arrays.asList ("D", "E", "F") ); } statisk tomrom usikkert (Liste ... l) {Objekt [] oArray = l; oArray [0] = Arrays.asList (ny Double (3.5)); Streng s = l [0] .get (0); }} 

De Objekt [] oArray = l; oppdrag introduserer muligheten for haugforurensning. En verdi som ikke samsvarer med den parameteriserte typen for varargs-parameteren l kan tilordnes variabel oArray. Imidlertid genererer ikke kompilatoren en ukontrollert advarsel fordi den allerede har gjort det når du oversetter Liste ... l til Liste [] l. Denne oppgaven er gyldig fordi variabel l har typen Liste[], hvilke undertyper Gjenstand[].

Kompilatoren utsteder heller ikke en advarsel eller feil når han tildeler en Liste objekt av hvilken som helst type til noen av oArray's array komponenter; for eksempel, oArray [0] = Arrays.asList (ny Double (3.5));. Denne oppgaven tilordnes den første matrisekomponenten i oArray en Liste objekt som inneholder en enkelt java.lang. dobbelt gjenstand.

De Streng s = l [0] .get (0); oppgave er problematisk. Objektet lagret i den første array-komponenten av variabelen l har typen Liste, men denne oppgaven forventer et objekt av typen Liste. Som et resultat kaster JVM java.lang.ClassCastException.

Kompiler denne kildekoden (javac -Xlint: ukontrollert UnsafeVarargsDemo.java). Du bør observere følgende utdata (litt omformatert for lesbarhet) når du kompilerer under Java SE 7 oppdatering 6:

 UnsafeVarargsDemo.java:8: advarsel: [ukontrollert] ukontrollert generering av generisk matrise for varargs-parameter av typen List [] usikker (Arrays.asList ("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: advarsel : [ukontrollert] Mulig haugforurensning fra parameterisert vararg-type Liste statisk ugyldig usikker (Liste ... l) ^ 2 advarsler 

I Java 101-introduksjonen min til generikk sa jeg at du ikke kan bruke typeparametere i array-creation-uttrykk. Du kan for eksempel ikke spesifisere elementer = ny E [størrelse];. Kompilatoren rapporterer en "generisk feil ved opprettingsfeil" når du prøver å gjøre det. Imidlertid er det fremdeles mulig å opprette en generisk matrise, men bare i en vargsammenheng, og det er hva den første advarselen melder om. Bak kulissene forvandler kompilatoren Liste ... l til Liste [] l og deretter til Liste [] l.

Legg merke til at varselet om forurensning av dyngen genereres på usikre () metodens erklæringssted. Denne meldingen genereres ikke på denne metodens anropsside, noe som er tilfelle med Java 5 og 6 kompilatorer.

Ikke alle varargsmetoder vil bidra til haugforurensning. Imidlertid vil det fortsatt bli utstedt en advarsel på metodens erklæringssted. Hvis du vet at metoden din ikke bidrar til haugforurensning, kan du undertrykke denne advarselen ved å erklære den med @SafeVarargs kommentar - Java 7 introduserte java.lang.SafeVarargs merknadstype. For eksempel fordi det ikke er noen måte for Arrays klassen asListe () metode for å bidra til haugforurensning, er denne metodens erklæring kommentert @SafeVarargs, som følger:

 @SafeVarargs public static List asList (T ... a) 

De @SafeVarargs annotering eliminerer generiske matriser og varselmeldinger om forurensning av dynger. Det er en dokumentert del av metodens kontrakt og hevder at metodens implementering ikke vil håndtere varargs formelle parameter feil.

For å konkludere

Java 7 forbedret utviklerens produktivitet ved å introdusere automatisk ressursadministrasjon via prøve-med-ressurs uttalelsen sammen med en ny Kan lukkes automatisk grensesnitt, innkoblingsstreng, multi-fangst, endelig omlegging, binære bokstaver, understreker i numeriske bokstaver, endringer i kompilatorens type inferensalgoritme som introduserte den såkalte diamantoperatøren, og forenklet varargs-metodeinnkallelse. Neste opp i Java 101: Neste generasjon serien er en titt på Java 8s lambda og funksjonelle grensesnitt språkfunksjoner.

Denne historien, "Java 101: The essential Java language features tour, Part 5" ble opprinnelig utgitt av JavaWorld.

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