2012-03-12 7 views
8

Sono pienamente consapevole che gli array generici non possono essere istanziati come tale:Perché sono autorizzato a dichiarare un array generico come variabile di istanza?

data = new Entry<K, V>[]; 

Questo si tradurrà in un errore:

Cannot create a generic array of Entry<K,V> 

Allora, perché ho il permesso di dichiarare una variabile di istanza che è un array di tipo generico senza errori?

+3

Dichiarando il tipo generico di un array, praticamente * solo * dichiara * l'intenzione * di usarlo come tale. Poiché il compilatore * non può * controllare i tipi generici e si può * facilmente * rompere il sistema di tipi con tipi generici negli array, il compilatore ti dirà quando stai facendo un'operazione che non può controllare. La migliore soluzione: evitare gli array quando si desidera che il compilatore verifichi la coerenza del tipo. –

+0

Vedere anche [Domande frequenti] di Angelika Langer (http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#Can%20I%20create%20an%20array%20whose%20component%20type%20is%20a%20concrete% 20instantiation% 20di% 20a% 20parameterized% 20type?) – McDowell

risposta

4

In linea di principio, il commento di Joachim Sauer è già la tua risposta, tuttavia, vorrei dettagliarlo un po '.

Sun (Oracle) conosce un fenomeno chiamato inquinamento della memoria, che si verifica sempre se un puntatore a variabili generiche punta a un oggetto non compatibile con il tipo. Questo può essere eseguita, ad esempio con il seguente codice:

List<String> list = new ArrayList<String>(); 
List<Number> numberList = (List<Number>)(List)list; 

, ovviamente, si inizierà a vedere ClassCastExceptions, una volta che si inizia a lavorare con quel codice. Questo è stato perfettamente accettabile per Sun quando si progettava Generics, perché si ottiene un avviso obbligatorio RawType/Unchecked conversion. Ogni volta che viene emesso questo avviso, si sa che si dispone di un codice, che non è controllato al 100% e che potrebbe verificarsi un inquinamento della memoria.

Il principio generale di progettazione in Generics è che tutti gli eventuali inquinamenti di memoria sono indicati da tali avvertimenti. Questo è il motivo per cui la creazione di array generici è proibita. Supponendo che non era, ecco cosa potrebbe accadere:

List<String>[] array = new List<String>[5]; 
Object[] oArray = array // this works without warning and has to for compatibility 
List<Object> oList = new ArrayList<Object>(); 
oArray[1] = oList; 

Avrete memoria-inquinamento lì senza alcun preavviso e per motivi di compatibilità, un avvertimento non può essere generato. Questo è il motivo per cui Sun ha deciso di vietare array di tipi generici. Tuttavia, le variabili potrebbero essere dichiarate perché si ottiene l'avviso di conversione non controllata lì e questo è tutto ciò che Sun desiderava: un avvertimento in caso di inquinamento.

2

Perché il compilatore e/o JIT devono essere in grado di dedurre i tipi generici.

Quando si tenta di creare un'istanza di Entry<K, V>[] il compilatore non può dedurre i tipi K e V, e quindi non si sarebbe in grado di creare l'oggetto reale (il che significa che il compilatore non riesce a trovare il giusto costruttore).

Tuttavia, se si dispone di un membro di tipo Entry<K, V>[] è solo un riferimento ad un tipo generico.
Il tipo corretto verrà dedotto quando viene utilizzato, in base al tipo effettivo che verrà assegnato ad esso. E poiché fa riferimento a un tipo effettivo, tutto il metodo che chiama i costruttori anc sarà deciso dal tipo a cui si fa riferimento.

Problemi correlati