2014-10-24 9 views
9

Ho il codice seguente:Java Generics è una decisione "Tutto o niente"?

public class Main { 
    public static void main(String[] args) { 
     Generic generic = new Generic<Integer>(5); 
     List<String> stringList = generic.getStringList(); // this line is where the compiler complains 
    } 
} 

public class Generic<T> { 
    private T member; 

    public Generic(T member) { 
     this.member = member; 
    } 

    public T getMember() { 
     return member; 
    } 

    public List<String> getStringList() { 
     return new ArrayList<String>(); 
    } 
} 

Nota che la classe Generic viene dichiarato con un parametro di tipo generico, ma la variabile generic nel metodo main è del tipo cancellazione, i. e. senza un parametro di tipo. Quello che non capisco è il motivo per cui il compilatore si lamenta la linea con l'assegnazione del List<String>:

Warning:(6, 56) java: unchecked conversion 
    required: java.util.List<java.lang.String> 
    found: java.util.List 

il metodo restituisce chiaramente un List<String>, indipendentemente dal parametro generico della classe. E questo è ciò che la variabile stringList prevede. Sembra che non utilizzare il parametro generico a livello di classe per la variabile generic disattiva l'elaborazione di tutti i generici e non solo quella in base al parametro di tipo della classe.

Sto utilizzando il compilatore Oracle Java 1.7.0_55 standard, se questo è importante.

Non sto chiedendo come eliminare l'avviso. So che dovrei dichiarare il tipo di variabile come Generic<Integer> o utilizzare @SuppressWarnings("unchecked"). Le mie domande sono le seguenti:

Questo comportamento è documentato?

Qual è il motivo di questo strano comportamento?

risposta

13

Quando si utilizza la cancellazione di un tipo, rimuove ogni traccia di farmaci generici - non solo gli usi del parametro di tipo T. Così il vostro generic atti variabili come se si riferisce a questo tipo:

// After type erasure 
public class Generic { 
    private Object member; 

    public Generic(Object member) { 
     this.member = member; 
    } 

    public Object getMember() { 
     return member; 
    } 

    public List getStringList() { 
     return new ArrayList(); 
    } 
} 

Questo è documentato nella JLS - partono da section 4.6 e seguire i link. Non è chiaro come potrebbe essere, ma è è documentato.

Il ragionamento è che se si utilizza un tipo non elaborato, il compilatore si aspetta che tu non sia a conoscenza dei generici - perché è probabile che stia compilando il codice pre-Java-5 legacy. Ciò si è dimostrato un po 'irrealistico nel tempo, ma credo che sia stata la motivazione per le specifiche a essere così.

+0

Penso in particolare alla frase "Tipo cancellazione associa anche la firma (§8.4.2) di un costruttore o un metodo a una firma che non ha tipi parametrizzati o variabili di tipo." del documento citato significa che tutti i parametri di tipo vengono rimossi da tutti i metodi, indipendentemente se sono collegati ai parametri di tipo della classe o meno. – FrankPl

3

Oltre alla risposta di Jon, quello che forse vuole fare è quello di dichiarare la variabile utilizzare ancora farmaci generici, ma accettare qualsiasi tipo:

Generic<?> generic = ...; 

Tralasciando il modificatore di tipo completamente sarà, come spiegato Jon, disabilitare anche altre dichiarazioni generiche non direttamente correlate al tipo di classe.

4

La risposta alla prima domanda è here.

particolare le linee:

Tipo cancellazione Mappe anche la firma (§8.4.2) di un costruttore o metodo per una firma che non ha tipi parametrici o digitare variabili. La cancellazione di un costruttore o di una firma del metodo s è una firma costituita dallo stesso nome di s e le cancellature di tutti i tipi di parametri formali forniti in s.

I parametri di tipo di un costruttore o metodo (§8.4.4), e il tipo ritorno (§8.4.5) di un metodo, subiscono anche cancellazione se la firma del costruttore o del metodo di viene cancellato.

La cancellazione della firma di un metodo generico non ha parametri di tipo .

Per quanto riguarda la ragione, la mia risposta è un po '"handwavy". Fondamentalmente, il sistema di tipi di Java era più debole di adesso, e Generics ha esposto alcuni dettagli di implementazione di basso livello che causano mal di testa. In particolare, ogni volta che si inserisce un elemento in un array, si incorre in un controllo del tipo in fase di esecuzione. Java arrays are covariant. Poiché durante il runtime si verifica un controllo del tipo e il comportamento di cancellazione come definito nella specifica, il compilatore desidera avvisare che è necessario essere a conoscenza di possibili problemi lungo la linea.

Quindi, più o meno, è una decisione di progettazione che ha causato un sacco di mal di testa dopo che i Generics sono stati implementati.