Java 101: Osnovni obilazak javanskog jezika, 5. dio

Prethodna 1 2 Stranica 2 Stranica 2 od 2

Tipsko zaključivanje i generički konstruktori za generičke i generičke klase

Generičke i generičke klase mogu deklarirati generičke konstruktore u kojima konstruktor ima formalni popis parametara tipa. Na primjer, možete generičkim konstruktorom proglasiti sljedeću generičku klasu:

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

Ova deklaracija navodi generičku klasu Boxs formalnim parametrom tipa E. Također navodi generički konstruktor s formalnim parametrom tipa T. Možete generirati generičku klasu i pozvati njen konstruktor na sljedeći način:

 new Box("Aggies") 

Ovaj izraz stvara instancu Box, prelazeći Marbleu E. Također, kompajler izvodi Stringkao Tstvarni argument tipa jer je argument konstruktora Stringobjekt.

Pre-Java 7 kompajleri zaključuju o stvarnim argumentima generičkog konstruktora slično onima iz generičke metode. Međutim, kompajler Java 7 može zaključiti na stvarne argumente tipa generičke klase koji se izrađuju u kontekstu dijamantskog operatora. Razmotrimo sljedeći primjer:

 Box box = new Box("Aggies"); 

Pored zaključivanja tipa Marbleza parametar formalnog tipa Egeneričke klase Box, kompajler izvodi tip Stringza parametar formalnog tipa Tkonstruktora ove generičke klase.

Mala promjena novčića za projekt br. 8: Pojednostavljeni poziv metode varargs

Prije Jave 7, svaki pokušaj pozivanja metode varargs (varijabilni argumenti, također poznati i kao varijabilni aritet ) s nereifabilnim tipom varargs uzrokovao je da je sastavljač dao upozorenje "nesigurna operacija". Da bi eliminirao potencijal za mnoge slične poruke upozorenja (po jednu po mjestu poziva), Java 7 je premjestila upozorenje sa mjesta poziva u deklaraciju metode.

Vrste koje se mogu ponovno montirati i koje se ne mogu popraviti

Reifiable tipa izlaže svoje potpune podatke tipa vrijeme izvođenja. Primjeri uključuju primitivne tipove, generičke tipove, sirove tipove i pozive nevezanih zamjenskih znakova. Suprotno tome, vrsta koja se ne može popraviti uklanja informacije o tipu u vrijeme sastavljanja brisanjem tipa, kako bi se osigurala binarna kompatibilnost s Java knjižnicama i aplikacijama koje su stvorene prije generičkih podataka. Primjeri uključuju Seti Set. Budući da ne reifiable tipa nije u potpunosti dostupan za vrijeme izvođenja, JVM ne može reći razliku između Sette Set; za vrijeme izvođenja dostupan je samo sirovi tip Set.

Generičke metode koje uključuju vararg ulazne parametre mogu prouzročiti onečišćenje hrpe , u kojem se varijabla parametriziranog tipa odnosi na objekt koji nije tog parametriziranog tipa (na primjer ako je sirovi tip pomiješan s parametriziranim tipom). Prevoditelj izvještava o "neprovjerenom upozorenju" jer se ne može provjeriti ispravnost operacije koja uključuje parametarski tip (poput lijevanja ili poziva metode).

Popis 13 pokazuje onečišćenje gomile u ne-varargovom kontekstu.

Popis 13. Demonstriranje onečišćenja gomile u ne-varargovom kontekstu

 import java.util.Iterator; import java.util.Set; import java.util.TreeSet; public class HeapPollutionDemo { public static void main(String[] args) { Set s = new TreeSet(); Set ss = s; // unchecked warning s.add(new Integer(42)); // another unchecked warning Iterator iter = ss.iterator(); while (iter.hasNext()) { String str = iter.next(); // ClassCastException thrown System.out.println(str); } } } 

Varijabla ssima parametarski tip Set. Kada se dodijeli ono na java.util.Setkoje se poziva , sastavljač generira neovjereno upozorenje. To čini zato što prevoditelj ne može odrediti da se odnosi na tip (ne zna). Rezultat je onečišćenje gomile. (Prevoditelj omogućuje ovoj dodjeli da sačuva povratnu kompatibilnost s naslijeđenim Java verzijama koje ne podržavaju generičke. Nadalje, brisanje tipa pretvara se u , što rezultira time da se jedna dodijeli drugoj .)ssssSetSetSetSetSet

Prevodilac generira drugu označenim upozorenje na liniji tog poziva Set„s add()metodom. To čini jer ne može odrediti sodnosi li se varijabla na tip Setili Settip. Ovo je još jedna situacija onečišćenja gomile. (Prevodilac dozvoljava ovaj način poziva zbog brisanja transformira Set„s boolean add(E e)metoda za boolean add(Object o)koje se može dodati bilo koju vrstu objekta na set, uključujući java.lang.Integerpodtip java.lang.Object.)

Zagađenje gomile može se lako dogoditi u kontekstu varargova. Na primjer, razmotrite Popis 14.

Popis 14. Demonstriranje onečišćenja gomile u kontekstu varargova

 import java.util.Arrays; import java.util.List; public class UnsafeVarargsDemo { public static void main(String[] args) { unsafe(Arrays.asList("A", "B", "C"), Arrays.asList("D", "E", "F")); } static void unsafe(List... l) { Object[] oArray = l; oArray[0] = Arrays.asList(new Double(3.5)); String s = l[0].get(0); } } 

Object[] oArray = l;Zadatak uvodi mogućnost onečišćenja gomila. Vrijednost koja se ne podudara s parametriziranim tipom parametra varargs lmože se dodijeliti varijabli oArray. Međutim, prevoditelj ne generira neprovjereno upozorenje jer je to već učinio prilikom prevođenja List... lu List[] l. Ova je dodjela valjana jer varijabla lima tip List[]koji podtipovi Object[].

Također, kompajler ne izdaje upozorenje ili pogrešku pri dodjeli Listobjekta bilo koje vrste bilo kojoj oArraykomponenti polja; npr oArray[0] = Arrays.asList(new Double(3.5));. Ovaj zadatak dodjeljuje se na prvo polje komponenta oArrayje Listobjekt koji sadrži jedan java.lang.Doubleobjekt.

String s = l[0].get(0);Zadatak je problematično. Objekt pohranjen u prvoj komponenti niza varijable lima tip List, ali ova dodjela očekuje objekt tipa List. Kao rezultat, JVM baca java.lang.ClassCastException.

Sastavite ovaj izvorni kod ( javac -Xlint:unchecked UnsafeVarargsDemo.java). Trebali biste primijetiti sljedeći izlaz (malo preformatiran radi čitljivosti) kada se kompajlira u Javi SE 7 ažuriranju 6:

 UnsafeVarargsDemo.java:8: warning: [unchecked] unchecked generic array creation for varargs parameter of type List[] unsafe(Arrays.asList("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: warning: [unchecked] Possible heap pollution from parameterized vararg type List static void unsafe(List... l) ^ 2 warnings 

U svom uvodu Java 101 u generike izjavio sam da ne možete koristiti parametre tipa u izrazima za stvaranje polja. Na primjer, ne možete odrediti elements = new E[size];. Prevoditelj izvještava o poruci "generička pogreška stvaranja niza" kada to pokušate učiniti. Međutim, još uvijek je moguće stvoriti generički niz, ali samo u kontekstu varargova, i to je ono što prva poruka upozorenja izvještava. Iza kulisa, kompajler se pretvara List... lu, List[] la zatim u List[] l.

Primijetite da se upozorenje o onečišćenju hrpom generira na unsafe()mjestu deklaracije metode. Ova se poruka ne generira na mjestu poziva ove metode, što je slučaj s kompajlerima Java 5 i 6.

Neće sve metode vararga pridonijeti zagađivanju gomile. Međutim, poruka upozorenja i dalje će se izdavati na mjestu deklaracije metode. Ako znate da vaša metoda ne pridonosi zagađivanju gomile, ovo upozorenje možete suzbiti deklariranjem s @SafeVarargsnapomenom - Java 7 je uvela java.lang.SafeVarargsvrstu bilješke. Na primjer, budući da metoda Arraysklase ne asList()može doprinijeti onečišćenju gomile, izjava ove metode označena je @SafeVarargskako slijedi:

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

@SafeVarargsKomentarima eliminira generički stvaranje polja i hrpu poruka upozorenja zagađenja. To je dokumentirani dio ugovora o metodi i tvrdi da implementacija metode neće nepropisno obrađivati ​​formalni parametar varargs.

U zaključku

Java 7 poboljšala je produktivnost programera uvođenjem automatskog upravljanja resursima putem izjave try-with-resources zajedno s novim AutoCloseablesučeljem, uključivanjem niza, višestrukim ulovom, konačnim ponovnim bacanjem, binarnim literalima, donjim crtama u numeričkim literalima, promjenama u tipu kompajlera algoritam zaključivanja koji je uveo takozvani dijamantni operater i pojednostavljeni poziv metode varargs. Sljedeće u Javi 101: Sljedeća generacija je pogled na značajke jezika Java Lambda i funkcionalnog sučelja.

Ovu je priču, "Java 101: obilazak osnovnih značajki Java jezika, 5. dio", izvorno objavio JavaWorld.