Programmering

Java 101: Det essentielle Java-sprog indeholder rundvisning, del 5

Forrige 1 2 Side 2 Side 2 af 2

Type inferens og generiske konstruktører til generiske og ikke-generiske klasser

Generiske og ikke-generiske klasser kan erklære generiske konstruktører, hvor en konstruktør har en formel 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æring specificerer generisk klasse Boks med formel typeparameter E. Det specificerer også en generisk konstruktør med formel typeparameter T. Du kan starte den generiske klasse og påkalde dens konstruktør som følger:

 ny kasse ("Aggies") 

Dette udtryk skaber en forekomst af Boks, passerer Marmor til E. Compileren udleder også Snor som T's faktiske type argument, fordi konstruktørens argument er en Snor objekt.

Pre-Java 7-kompilatorer udleder en generisk konstruktørs faktiske typeargumenter svarende til dem fra en generisk metode. Java 7's kompilator kan imidlertid udlede de faktiske typeargumenter for den generiske klasse, der instantieres i en diamantoperatørsammenhæng. Overvej følgende eksempel:

 Box box = new Box ("Aggies"); 

Samt udlede typen Marmor for formel type parameter E af generisk klasse Boks, compileren udleder typen Snor for formel type parameter T af denne generiske klasses konstruktør.

Projektmønt lille ændring # 8: Forenklet påkaldelse af varargs-metoden

Før Java 7 forsøger hvert at påberåbe sig en varargs (variable argumenter, også kendt som variabel aritet) -metode med en ikke-genoprettelig varargs-type fik compileren til at udsende en "usikker operation" -advarsel. For at eliminere potentialet for mange lignende advarselsmeddelelser (en pr. Opkaldssite) flyttede Java 7 advarslen fra opkaldsstedet til metodedeklarationen.

Genanvendelige og ikke-genanvendelige typer

EN genoprettelig type eksponerer dens komplette typeoplysninger ved kørselstid. Eksempler inkluderer primitive typer, ikke-generiske typer, rå typer og påkald af ubundne jokertegn. I modsætning hertil a ikke-genindvindelig type har fjernet typeoplysninger på kompileringstidspunktet efter sletning af typen for at sikre binær kompatibilitet med Java-biblioteker og applikationer, der blev oprettet før generiske. Eksempler inkluderer Sæt og Sæt. Da en ikke-repeterbar type ikke er fuldstændig tilgængelig under kørsel, kan JVM ikke se forskellen på Sæt og Sæt; ved kørsel, kun den rå type Sæt er tilgængelig.

Generiske metoder, der inkluderer vararg-inputparametre, kan forårsage bunkeforurening, hvor en variabel af en parametreret type henviser til et objekt, der ikke er af den parametriserede type (for eksempel hvis en rå type er blevet blandet med en parametreret type). Compileren rapporterer en "ikke-markeret advarsel", fordi rigtigheden af ​​en operation, der involverer en parametreret type (som et cast eller metodekald) ikke kan verificeres.

Liste 13 viser dyngeforurening i en ikke-varargs sammenhæng.

Liste 13. Demonstration af bunkeforurening i en ikke-vargsammenhæng

 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 (); Indstil ss = s; // ukontrolleret advarsel s.add (nyt heltal (42)); // en anden ukontrolleret advarsel Iterator iter = ss.iterator (); mens (iter.hasNext ()) {String str = iter.next (); // ClassCastException kastet System.out.println (str); }}} 

Variabel ss har parametreret type Sæt. Når java.util.Set det refereres af s er tildelt ss, genererer compileren en ukontrolleret advarsel. Det gør det, fordi compileren ikke kan bestemme det s henviser til en Sæt type (det gør det ikke). Resultatet er forurening af dynger. (Compileren tillader, at denne opgave bevarer bagudkompatibilitet med ældre Java-versioner, der ikke understøtter generics. Desuden skriver sletningstransformationer Sæt ind i Sæt, hvilket resulterer i en Sæt bliver tildelt en anden Sæt.)

Compileren genererer en anden ukontrolleret advarsel på den linje, der påberåber sig Sæt's tilføje() metode. Det gør det, fordi det ikke kan afgøre, om variabelt s henviser til en Sæt eller Sæt type. Dette er en anden situation med bunkeforurening. (Compileren tillader denne metodeopkald, fordi sletning transformeres Sæt's boolsk tilføjelse (E e) metode til boolsk tilføjelse (Objekt o), som kan tilføje enhver form for objekt til sættet, inklusive java.lang. heltal undertype af java.lang.Objekt.)

Bunkeforurening kan let forekomme i en varargs sammenhæng. Overvej f.eks. Listing 14.

Liste 14. Demonstration af bunkeforurening i en varargs sammenhæng

 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 ugyldigt usikkert (Liste ... l) {Objekt [] oArray = l; oArray [0] = Arrays.asList (ny dobbelt (3.5)); Streng s = l [0] .get (0); }} 

Det Objekt [] oArray = l; opgave introducerer muligheden for dyngeforurening. En værdi, der ikke matcher den parametriserede type af varargs-parameteren l kan tildeles variabel oArray. Imidlertid genererer compileren ikke en ukontrolleret advarsel, fordi den allerede har gjort det under oversættelse Liste ... l til Liste [] l. Denne opgave er gyldig, fordi variabel l har typen Liste[], hvilke undertyper Objekt[].

Compileren udsender heller ikke en advarsel eller fejl, når han tildeler en Liste objekt af enhver art til nogen af oArray's array komponenter for eksempel, oArray [0] = Arrays.asList (ny dobbelt (3.5));. Denne opgave tildeles den første array-komponent i oArray -en Liste objekt, der indeholder en enkelt java.lang. dobbelt objekt.

Det Streng s = l [0] .get (0); opgave er problematisk. Objektet gemt i den første array-komponent i variablen l har typen Liste, men denne opgave forventer et objekt af typen Liste. Som et resultat kaster JVM java.lang.ClassCastException.

Kompilér denne kildekode (javac -Xlint: ikke markeret UnsafeVarargsDemo.java). Du skal overholde følgende output (let omformateret for læsbarhed), når du kompilerer under Java SE 7 opdatering 6:

 UnsafeVarargsDemo.java:8: advarsel: [ukontrolleret] ikke markeret generisk matrix oprettelse for varargs parameter af typen Liste [] usikker (Arrays.asList ("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: advarsel : [ukontrolleret] Mulig dyngforurening fra parametreret vararg-type Liste statisk ugyldigt usikkert (Liste ... l) ^ 2 advarsler 

I min Java 101 introduktion til generics sagde jeg, at du ikke kan bruge typeparametre i array-creation-udtryk. For eksempel kan du ikke angive elementer = ny E [størrelse];. Compileren rapporterer en "generisk array-oprettelsesfejl" -meddelelse, når du prøver at gøre det. Det er dog stadig muligt at oprette et generisk array, men kun i en vargs-sammenhæng, og det er det, den første advarselsmeddelelse rapporterer. Bag kulisserne transformerer compileren Liste ... l til Liste [] l og derefter til Liste [] l.

Bemærk, at advarslen om forurening af bunker genereres på usikre () metodens erklæringssted. Denne meddelelse genereres ikke på denne metodes opkaldsside, hvilket er tilfældet med Java 5 og 6 compilere.

Ikke alle varargs-metoder vil bidrage til dyngeforurening. Der vil dog stadig blive udsendt en advarselsmeddelelse på metodens erklæringssted. Hvis du ved, at din metode ikke bidrager til dyngeforurening, kan du undertrykke denne advarsel ved at erklære den med @SafeVarargs kommentar - Java 7 introducerede java.lang.SafeVarargs annoteringstype. For eksempel fordi der ikke er nogen måde for Arrays klassens asList () metode til at bidrage til dyngeforurening, er denne metodes erklæring kommenteret med @SafeVarargs, som følger:

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

Det @SafeVarargs annotation eliminerer generiske array-oprettelser og advarselsmeddelelser om bunkeforurening. Det er en dokumenteret del af metodens kontrakt og hævder, at metodens implementering ikke forkert håndterer den formelle parameter varargs.

Afslutningsvis

Java 7 forbedrede udviklerens produktivitet ved at indføre automatisk ressourcestyring via erklæringen prøve-med-ressourcer sammen med en ny Kan lukkes automatisk interface, switch-on-string, multi-catch, final rethrow, binære bogstaver, understregninger i numeriske bogstaver, ændringer til kompilatorens type inferensalgoritme, der introducerede den såkaldte diamantoperator og forenklet varargs-metodeindkaldelse. Næste op i Java 101: Den næste generation serien er et kig på Java 8s lambda og funktionelle interface sprogfunktioner.

Denne historie, "Java 101: The essential Java language features tour, Part 5" blev oprindeligt udgivet af JavaWorld.