Zadejte odvození a generické konstruktory pro obecné a negenerické třídy
Obecné a negenerické třídy mohou deklarovat obecné konstruktory, ve kterých má konstruktor formální seznam parametrů typu. Můžete například deklarovat následující obecnou třídu pomocí generického konstruktoru:
public class Box {public Box (T t) {// ...}}
Toto prohlášení určuje obecnou třídu Krabice
s parametrem formálního typu E
. Určuje také obecný konstruktor s parametrem formálního typu T
. Generickou třídu můžete vytvořit instanci a vyvolat její konstruktor následujícím způsobem:
nový rámeček („Aggies“)
Tento výraz vytvoří instanci Krabice
projíždějící Mramor
na E
. Kompilátor také odvozuje Tětiva
tak jako T
Skutečný argument typu, protože argument konstruktoru je a Tětiva
objekt.
Kompilátory z Pre-Java 7 odvozují argumenty skutečného typu generického konstruktoru podobně jako argumenty generické metody. Kompilátor prostředí Java 7 však může odvodit argumenty skutečného typu generické třídy, která je vytvořena v kontextu operátoru diamantu. Zvažte následující příklad:
Box box = nový Box ("Aggies");
Stejně jako odvození typu Mramor
pro parametr formálního typu E
generické třídy Krabice
, odvozuje typ kompilátoru Tětiva
pro parametr formálního typu T
konstruktoru této generické třídy.
Malá změna projektu Coin # 8: Zjednodušené vyvolání metody varargs
Před Javou 7 se každý pokus vyvolat varargs (proměnné argumenty, známé také jako variabilní arity) metoda s nerefikovatelným typem varargs způsobila, že kompilátor vydal varování „nebezpečná operace“. Aby se eliminoval potenciál mnoha podobných varovných zpráv (jedna na web volání), Java 7 přesunula varování z webu volání do deklarace metody.
Reifiable a non-reifiable typy
A opakovatelný typ vystavuje své úplné informace o typu za běhu. Mezi příklady patří primitivní typy, negenerické typy, nezpracované typy a vyvolání nevázaných zástupných znaků. Naproti tomu a nenahraditelný typ má informace o typu odstraněny v době kompilace vymazáním typu, aby byla zajištěna binární kompatibilita s knihovnami Java a aplikacemi, které byly vytvořeny před generikami. Mezi příklady patří Soubor
a Soubor
. Protože typ, který nelze znovu identifikovat, není za běhu zcela k dispozici, nemůže JVM rozlišit rozdíl mezi Soubor
a Soubor
; za běhu pouze surový typ Soubor
je k dispozici.
Mohou způsobit obecné metody, které zahrnují vstupní parametry vararg haldy znečištění, ve kterém proměnná parametrizovaného typu odkazuje na objekt, který není tohoto parametrizovaného typu (například pokud byl smíchán surový typ s parametrizovaným typem). Kompilátor hlásí „nezaškrtnuté varování“, protože správnost operace zahrnující parametrizovaný typ (jako přetypování nebo volání metody) nelze ověřit.
Výpis 13 demonstruje znečištění haldy v kontextu bez variací.
Výpis 13. Demonstrace znečištění haldy v kontextu bez variací
import java.util.Iterator; import java.util.Set; import java.util.TreeSet; veřejná třída HeapPollutionDemo {public static void main (String [] args) {Set s = new TreeSet (); Nastavit ss = s; // nezaškrtnuté varování s.add (new Integer (42)); // další nezaškrtnuté varování Iterator iter = ss.iterator (); while (iter.hasNext ()) {String str = iter.next (); // ClassCastException vyvolána System.out.println (str); }}}
Variabilní ss
má parametrizovaný typ Soubor
. Když sada java.util
na které odkazuje s
je přiřazen ss
, kompilátor generuje nezaškrtnuté varování. Činí tak proto, že to překladač nemůže určit s
označuje a Soubor
typ (není). Výsledkem je znečištění haldy. (Kompilátor umožňuje tomuto přiřazení zachovat zpětnou kompatibilitu se staršími verzemi prostředí Java, které nepodporují generika. Dále transformace mazání typu Soubor
do Soubor
, jehož výsledkem je jeden Soubor
byl přidělen jinému Soubor
.)
Kompilátor generuje druhé nezaškrtnuté varování na řádku, který vyvolá Soubor
je přidat()
metoda. Činí tak proto, že nemůže určit, zda je proměnná s
označuje a Soubor
nebo Soubor
typ. Toto je další situace znečištění haldy. (Kompilátor umožňuje toto volání metody, protože mazání se transformuje Soubor
je boolean add (E e)
metoda k boolean add (Objekt o)
, který může do sady přidat jakýkoli druh objektu, včetně java.lang.Integer
podtyp java.lang.Object
.)
Znečištění haldy může snadno nastat v kontextu varargs. Zvažte například výpis 14.
Výpis 14. Demonstrace znečištění haldy v kontextu varargs
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 (nový Double (3.5)); Řetězec s = l [0] .get (0); }}
The Objekt [] oArray = l;
zadání zavádí možnost znečištění haldy. Hodnota neodpovídající parametrizovanému typu parametru varargs l
lze přiřadit k proměnné oArray
. Kompilátor však nevygeneruje nezaškrtnuté varování, protože tak již učinil při překladu Seznam ... l
na Seznam [] l
. Toto přiřazení je platné, protože proměnná l
má typ Seznam[]
, které podtypy Objekt[]
.
Kompilátor také nevydává varování nebo chybu při přiřazování a Seznam
objekt libovolného typu na některý z oArray
komponenty pole; například, oArray [0] = Arrays.asList (nový Double (3.5));
. Toto přiřazení se přiřadí první komponentě pole oArray
A Seznam
objekt obsahující jediný java.lang.Double
objekt.
The Řetězec s = l [0] .get (0);
přiřazení je problematické. Objekt uložený v první komponentě pole proměnné l
má typ Seznam
, ale toto přiřazení očekává objekt typu Seznam
. Výsledkem je, že JVM hodí java.lang.ClassCastException
.
Zkompilovat tento zdrojový kód (javac -Xlint: nezaškrtnuto UnsafeVarargsDemo.java
). Při kompilaci pod aktualizací Java SE 7 aktualizace 6 byste měli dodržovat následující výstup (mírně přeformátovaný kvůli čitelnosti):
UnsafeVarargsDemo.java:8: varování: [nezaškrtnuto] nekontrolované vytvoření obecného pole pro parametr varargs typu List [] nebezpečné (Arrays.asList ("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: varování : [nezaškrtnuto] Možné znečištění haldy parametrizovaným typem vararg Seznam statických neplatných nebezpečných (Seznam ... l) ^ 2 varování
V mém úvodu k generikům Java 101 jsem uvedl, že ve výrazech pro vytváření matic nemůžete použít parametry typu. Například nemůžete určit elements = new E [size];
. Když se o to pokusíte, kompilátor ohlásí zprávu „chyba při vytváření obecného pole“. Stále je však možné vytvořit obecné pole, ale pouze v kontextu varargs, a to hlásí první varovná zpráva. V zákulisí se kompilátor transformuje Seznam ... l
na Seznam [] l
a pak do Seznam [] l
.
Všimněte si, že varování před hromadou znečištění je generováno na nebezpečný()
stránka deklarace metody. Tato zpráva není generována na stránce volání této metody, což je případ kompilátorů Java 5 a 6.
Ne všechny metody Varargs přispějí ke znečištění haldy. Na místě deklarace metody však bude stále vydána varovná zpráva. Pokud víte, že vaše metoda nepřispívá ke znečištění haldy, můžete toto varování potlačit deklarací pomocí @SafeVarargs
anotace - Java 7 představila java.lang.SafeVarargs
typ poznámky. Například proto, že neexistuje způsob, jak Pole
třídy asList ()
metoda, která přispívá ke znečištění haldy, byla tato deklarace této metody anotována @SafeVarargs
, jak následuje:
@SafeVarargs public static List asList (T ... a)
The @SafeVarargs
anotace eliminuje generické vytváření pole a varovné zprávy o znečištění haldy. Je to zdokumentovaná část kontraktu metody a tvrdí, že implementace metody nebude nesprávně zpracovávat formální parametr varargs.
Závěrem
Java 7 zlepšila produktivitu vývojářů zavedením automatické správy zdrojů prostřednictvím příkazu try-with-resources společně s novým Automaticky uzavíratelné
interface, switch-on-string, multi-catch, final rethrow, binární literály, podtržítka v numerických literálech, změny algoritmu odvození typu kompilátoru, který zavedl takzvaný diamantový operátor, a zjednodušené vyvolání metody varargs. Další v Java 101: Nová generace série je pohled na lambda a funkční jazykové funkce rozhraní Java 8.
Tento příběh, „Java 101: Prohlídka základních funkcí jazyka Java, část 5“, původně publikoval JavaWorld.