2015-01-17 9 views
6

Si consideri il seguente codiceMetodo generico Java. Perché viene dedotto T come mappa?

class MyClass { 
    public MyClass(Map<String, String> m) { 
     System.out.println("map"); 
    } 

    public MyClass(SortedMap<String, String> m) { 
     System.out.println("sortedmap"); 
    } 
} 
public class Test { 

    public <T extends Map<String,String>> Test(T t) { 
     new MyClass(t); 
    } 

    public static void main(String[] args) { 
     new Test(new TreeMap<String,String>()); 
    } 

} 

Esso stampa map. Perché è T dedotto per essere Map anziché SortedMap in public <T extends Map<String, String>> Test(T t)? C'è un modo per modificare questo comportamento al fine di utilizzare il costruttore più concreto per MyClass?

risposta

4

La risoluzione del costruttore di MyClass viene eseguita al momento della compilazione. Quando il compilatore compila il codice del costruttore Test, non sa cosa sia in realtà T, sa solo che è garantito essere un Map<String, String>, quindi non può fare nient'altro che legare la chiamata del costruttore al costruttore che prende un Map . La conoscenza che nel codice T è un TreeMap è presente solo all'interno del corpo del metodo main, non all'esterno. Si consideri, ad esempio, cosa succederebbe se aggiungessi un secondo chiamante del costruttore Test che effettivamente supera uno HashMap.

generici Java funzionano in modo tale che il codice di un metodo generico viene compilata una sola volta per tutti i possibili valori dei parametri generici (e presente solo una volta nel codice byte), non è come in altre lingue una copia del metodo generico per ogni tipo generico.

In generale, non è possibile in Java per lasciare una singola chiamata di metodo/costruttore nel codice effettivamente chiamare diversi metodi/costruttori in fase di esecuzione a seconda del tipo di argomenti. Questo è possibile solo per le chiamate di metodo a seconda del tipo di runtime dell'oggetto chiamato (associazione dinamica con metodi sovrascritti).

Il sovraccarico (quello che hai qui) funziona solo in fase di compilazione osservando il tipo statico degli argomenti.

La soluzione tipica per questa situazione consiste nell'utilizzare un controllo instanceof SortedMap all'interno del costruttore di MyClass. Un'altra possibile (più elegante) soluzione è il pattern visitor, ma funziona solo con le classi che sono state preparate per questo (quindi non con le istanze Map se non le si avvolge in una classe propria).

+0

Come è possibile che il compilatore non sappia che tipo 'T' sia effettivamente? Lo sto costruendo come un 'TreeMap' (capirò il comportamento se il costruttore è stato invocato passando un oggetto dichiarato come' Map' che era veramente un 'TreeMap', ma non è questo il caso) –

+2

Oh, mi aspettavo per generare codice diverso per diverse versioni di 'T' nello stesso metodo generico. Suppongo che Java non sia C++. Grazie per la risposta, ora è chiaro. –

Problemi correlati