Zadajte odvodenie a generické konštruktory pre všeobecné a negenerické triedy
Generické a negenerické triedy môžu deklarovať generické konštruktory, v ktorých má konštruktor formálny zoznam parametrov typu. Môžete napríklad deklarovať nasledujúcu generickú triedu pomocou generického konštruktora:
public class Box {public Box (T t) {// ...}}
Toto vyhlásenie určuje všeobecnú triedu Krabica
s parametrom formálneho typu E
. Tiež určuje všeobecný konštruktor s parametrom formálneho typu T
. Generickú triedu môžete vytvoriť inštanciou a vyvolať jej konštruktor nasledovne:
nový box („Aggies“)
Tento výraz vytvára inštanciu Krabica
, absolvovanie Mramor
do E
. Kompilátor tiež odvodzuje String
ako T
skutočný argument typu, pretože argumentom konštruktora je a String
objekt.
Kompilátory pred Java 7 odvodzujú argumenty skutočného typu generického konštruktora podobne ako argumenty generickej metódy. Kompilátor Java 7 však môže odvodiť argumenty skutočného typu generickej triedy, ktorá je inštancovaná v kontexte diamantového operátora. Uvažujme o nasledujúcom príklade:
Box box = nový Box („Aggies“);
Rovnako ako vyvodenie typu Mramor
pre parameter formálneho typu E
generickej triedy Krabica
, odvodzuje typ kompilátora String
pre parameter formálneho typu T
konštruktora tejto generickej triedy.
Malá zmena projektu Coin # 8: Zjednodušené vyvolanie metódy varargs
Pred jazykom Java 7 sa každý pokus o vyvolanie varargs (argumenty premenných, tiež známych ako variabilná aritita) metóda s typom nevarovateľných varargs spôsobila, že kompilátor vydal varovanie „nebezpečná operácia“. Aby sa eliminoval potenciál mnohých podobných varovných správ (jedna na stránku hovoru), Java 7 presunula varovanie zo stránky hovoru na deklaráciu metódy.
Obnoviteľné a nerefikovateľné typy
A opakovateľný typ vystavuje svoje úplné informácie o type za behu. Príklady zahŕňajú primitívne typy, negenerické typy, nespracované typy a vyvolanie neviazaných zástupných znakov. Naproti tomu a nereferovateľný typ má informácie o type odstránené v čase kompilácie vymazaním typu, aby bola zaistená binárna kompatibilita s knižnicami Java a aplikáciami, ktoré boli vytvorené pred generikami. Príklady zahŕňajú Nastaviť
a Nastaviť
. Pretože typ, ktorý sa nedá opätovne vymeniť, nie je za behu úplne k dispozícii, server JVM nedokáže rozlíšiť medzi Nastaviť
a Nastaviť
; za behu iba surový typ Nastaviť
je k dispozícii.
Môžu spôsobiť všeobecné metódy, ktoré zahŕňajú vstupné parametre vararg halda znečistenie, v ktorom premenná parametrizovaného typu odkazuje na objekt, ktorý nie je tohto parametrizovaného typu (napríklad ak bol zmiešaný surový typ s parametrizovaným typom). Kompilátor nahlási „nezaškrtnuté varovanie“, pretože nie je možné overiť správnosť operácie týkajúcej sa parametrizovaného typu (napríklad obsadenie alebo volanie metódy).
Výpis 13 demonštruje haldy znečistenia v prostredí, ktoré nie je variabilné.
Zoznam 13. Preukazovanie znečistenia haldy v kontexte, ktorý nie je variabilný
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 (); Nastaviť ss = s; // nezaškrtnuté varovanie s.add (new Integer (42)); // ďalšie nezaškrtnuté varovanie Iterator iter = ss.iterator (); while (iter.hasNext ()) {String str = iter.next (); // ClassCastException vyvolaná System.out.println (str); }}}
Variabilné ss
má parametrizovaný typ Nastaviť
. Keď java.util.Set
na ktoré odkazuje s
je priradený k ss
, kompilátor vygeneruje nekontrolované varovanie. Robí to preto, lebo to kompilátor nedokáže určiť s
označuje a Nastaviť
typu (nie je). Výsledkom je halda znečistenia. (Kompilátor umožňuje tomuto priradeniu zachovať spätnú kompatibilitu so staršími verziami Java, ktoré nepodporujú generické typy. Ďalej, transformácie mazania typu Nastaviť
do Nastaviť
, ktorého výsledkom je jeden Nastaviť
bol pridelený inému Nastaviť
.)
Kompilátor vygeneruje druhé nezaškrtnuté varovanie na riadku, ktorý vyvolá Nastaviť
je pridať ()
metóda. Robí to preto, lebo nedokáže určiť, či je premenná s
označuje a Nastaviť
alebo Nastaviť
typu. Toto je ďalšia situácia so znečistením haldy. (Kompilátor umožňuje toto volanie metódy, pretože mazanie sa transformuje Nastaviť
je boolovský prírastok (E e)
metóda do boolean add (Objekt o)
, ktorý môže do sady pridať akýkoľvek druh objektu, vrátane java.lang.Integer
podtyp java.lang.Objekt
.)
Znečistenie haldy sa môže ľahko vyskytnúť v rôznych variantoch. Zvážte napríklad záznam č. 14.
Zoznam 14. Preukazovanie znečistenia haldy v kontexte varargs
importovať 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 (nový Double (3.5)); Reťazec s = l [0] .get (0); }}
The Objekt [] oArray = l;
zadanie predstavuje možnosť znečistenia haldy. Hodnota, ktorá sa nezhoduje s parametrizovaným typom parametra varargs l
možno priradiť k premennej oArray
. Kompilátor však negeneruje nezaškrtnuté varovanie, pretože tak už urobil pri preklade Zoznam ... l
do Zoznam [] l
. Toto priradenie je platné, pretože premenná l
má typ Zoznam []
, ktoré podtypy Objekt []
.
Kompilátor tiež nevydá varovanie ani chybu pri priradení a Zoznam
objekt ľubovoľného typu na ktorýkoľvek z oArray
komponenty poľa; napríklad, oArray [0] = Arrays.asList (nový Double (3.5));
. Toto priradenie sa priradí k prvej zložke poľa v oArray
a Zoznam
objekt obsahujúci jednu java.lang.Double
objekt.
The Reťazec s = l [0] .get (0);
zadanie je problematické. Objekt uložený v prvom komponente poľa premennej l
má typ Zoznam
, ale toto priradenie očakáva objekt typu Zoznam
. Vo výsledku vhadzuje JVM java.lang.ClassCastException
.
Zostavte tento zdrojový kód (javac -Xlint: nezačiarknuté políčko UnsafeVarargsDemo.java
). Pri kompilácii pod aktualizáciou Java SE 7, verzia 6, by ste mali dodržiavať nasledujúci výstup (mierne preformátovaný kvôli čitateľnosti):
UnsafeVarargsDemo.java:8: varovanie: [nezačiarknuté] nekontrolované vytvorenie generického poľa pre parameter varargs typu List [] nebezpečné (Arrays.asList ("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: varovanie : [nezačiarknuté] Možné znečistenie haldy parametrizovaným typom vararg Zoznam statických neplatných nebezpečných (Zoznam ... l) ^ 2 varovania
V mojom úvode do generík v jazyku Java 101 som uviedol, že vo výrazoch na vytváranie polí nemôžete používať parametre typu. Napríklad nemôžete určiť prvky = nový E [veľkosť];
. Keď sa o to pokúsite, kompilátor nahlási správu „chyba pri vytváraní generického poľa“. Stále je však možné vytvoriť všeobecné pole, ale iba v kontexte varargs, a to je hlásenie prvej varovnej správy. V zákulisí sa prekladač transformuje Zoznam ... l
do Zoznam [] l
a potom do Zoznam [] l
.
Všimnite si, že varovanie pred haldou sa generuje na nebezpečný ()
stránka deklarácie metódy. Táto správa sa negeneruje na stránke volania tejto metódy, čo je prípad kompilátorov Java 5 a 6.
Nie všetky varargsove metódy prispejú k znečisteniu haldy. Na mieste deklarácie metódy však bude stále vydaná varovná správa. Ak viete, že vaša metóda neprispieva k znečisteniu haldy, môžete toto varovanie potlačiť vyhlásením pomocou @SafeVarargs
anotácia - Java 7 predstavila java.lang.SafeVarargs
typ anotácie. Napríklad preto, lebo neexistuje spôsob, ako Polia
triedy asList ()
metóda prispievajúca k hromadeniu znečistenia, vyhlásenie tejto metódy bolo anotované @SafeVarargs
, nasledovne:
@SafeVarargs verejný statický zoznam ako zoznam (T ... a)
The @SafeVarargs
anotácia eliminuje vytváranie generických polí a varovné správy o znečistení haldy. Je to zdokumentovaná súčasť zmluvy o metóde a tvrdí, že implementácia metódy nebude nesprávne spracovávať formálny parameter varargs.
Na záver
Java 7 zlepšila produktivitu vývojárov zavedením automatickej správy zdrojov prostredníctvom príkazu try-with-resources spolu s novým Automatické uzatváranie
rozhranie, switch-on-string, multi-catch, final rethrow, binárne literály, podčiarkovníky v numerických literáloch, zmeny v algoritme odvodzovania typu kompilátora, ktorý zaviedol takzvaného diamantového operátora, a zjednodušené vyvolanie varargsovej metódy. Ďalej na Java 101: Nová generácia séria predstavuje pohľad na lambda a funkčné jazykové vlastnosti rozhrania Java 8.
Tento príbeh, „Java 101: Prehliadka základných funkcií jazyka Java, časť 5“, bol pôvodne publikovaný spoločnosťou JavaWorld.