2013-02-12 15 views
7

Ho un problema con la comprensione tale metodo generico invocazione:metodo generico invocazione con <T>

object = ObjectGenerator.<T> getObject(objectName); 

Ecco che arriva un contesto per sopra situazione:

class GenClass<T> { 

    private T object; 

    // ... some code 

    public void initObject(String objectName) { 
     object = ObjectGenerator.<T> getObject(objectName); 
    } 
} 

class ObjectGenerator { 

    public static <T extends Object> T getObject(String name) { 
     // some code 
     return someObject; 
    } 
} 

La domanda è: quale ruolo gioca <T> prima getObject(objectName) invocazione?

+1

+1 perché non l'ho visto prima. –

+0

Non mi sto chiedendo in che senso, ma solo su una riga di codice. Posso cambiare la firma del metodo in ' T getObject (String name, Class clazz)' - non importa. Solo questa riga con invocazione di quel metodo con '' mi confonde per me – emka86

risposta

7

Nota: nell'esempio specifico specificato, ObjectGenerator.getObject(objectName); deve essere compilato correttamente.

In alcune situazioni, il meccanismo di inferenza di tipo non permette di risolvere il fatto che in:

T object; 
object = ObjectGenerator.getObject(objectName); 

tipo restituito dovrebbe essere T. In tal caso, è necessario fornire al compilatore un piccolo aiuto indicando esplicitamente il tipo di reso che ci si aspetta.

Ecco un esempio forzato in cui è necessario specificare esplicitamente il tipo generico:

class Example { 
    public static <T> List<T> m1() { 
     return m2(Arrays.<T> asList()); //Arrays.asList() would not compile 
    } 
    public static <T> List<T> m2(List<T> l) { 
     return l; 
    } 
} 
+0

In quali situazioni il "meccanismo di inferenza del tipo" non è in grado di sapere quale dovrebbe essere il tipo restituito? – asteri

+0

@Jeff Ho aggiunto un esempio: le situazioni esatte in cui ciò accade dipende dal risultato dell'applicazione delle [regole di inferenza del tipo] (http://docs.oracle.com/javase/specs/jls/se7/html/jls- 15.html # jls-15.12.2.7), che sono circa 12 pagine nella versione pdf del JLS, quindi non completamente sicuro di essere onesto. Alla fine il modo in cui lo guardo è: o si compila senza il tipo esplicito e sono felice o non lo è e lo aggiungo semplicemente ... – assylias

+0

Sì, ho capito! Questa è una spiegazione molto buona per me e guardando questa specifica dal tuo link Immagino che ci siano molte altre brutte situazioni da scoprire! :) – emka86

0

object può essere figlio di T.

Naturalmente getObject dovrebbe meglio sono stati definiti:

public static <T> T getObject(Class<T> objectClass, String name) { 
    return objectClass.getConstructor(String.class).newInstance(name); 
    //return objectClass.getConstructor().newInstance(); 
} 

altrimenti non c'è nessun tipo di costruzione sicura possibile, a causa del cosiddetto tipo di cancellazione.

-1
object = ObjectGenerator.getObject(objectName); 

restituisce sempre oggetto di oggetto dal momento che si sta chiamando un metodo statico. Per ottenere in modo esplicito l'oggetto generico è stato utilizzato per la T, nel codice,

object = ObjectGenerator.<T> getObject(objectName); 

<T> viene utilizzato in contesto statico. Per invocazione non statica non è necessario.

+0

-1 Il contesto statico non ha nulla a che fare con l'offerta esplicita di argomenti tipo. –

+0

grazie per avermi illuminato :) – prasanth

0

Ho trovato qualcosa qui: https://stackoverflow.com/a/338906/443427 può aiutarti.

Da quanto ho letto può rappresentare il generico che compilatore deve utilizzare per calcolare il tipo di valore riaccordata, per passare la generica avanti

come nota anche questo funziona bene (controllare l'ObjectGenerator differisce da T):

public class ObjectGenerator<X> { 
    public static <T extends Object> Set<T> getObject(String name) { 
    // some code 
    return null; 
    } 
} 
0

io non del tutto d'accordo con la risposta accettata, in cui si dice:

in tal caso, è necessario dare al compilatore un piccolo aiuto da parte esplicitamente indicando il tipo di reso che ti aspetti.

Questo non mi sembra giusto. Come comprendo il metodo generico e l'inferenza del tipo, il tipo fornito tra parentesi quadre non indica direttamente il tipo di ritorno del metodo generico. Piuttosto, il tipo T potrebbe essere il tipo restituito, il tipo di argomento, il tipo di variabile locale associato al metodo generico.

In realtà, grazie al meccanismo di inferenza del tipo, non è necessario specificare il parametro tipo T nella maggior parte dei casi (non solo in alcune situazioni). Nel tuo esempio, il <T> può essere tranquillamente omesso dall'invocazione del metodo ObjectGenerator.<T> getObject(objectName) come nella maggior parte degli altri casi. Questo perché il tipo T del metodo generico può essere facilmente dedotto da il tipo a cui viene assegnato il risultato o restituito. In altre parole, poiché si dichiara private T object prima del richiamo del metodo, il tipo T verrà dedotto correttamente come T.

La mia domanda può essere sostenuta dalla seguente dichiarazione a definitive tutorial:

tipo inferenza è la capacità di un compilatore Java per guardare ogni metodo invocazione e corrispondente dichiarazione per determinare il tipo argomento (o argomenti) che rendono applicabile l'invocazione. L'algoritmo di inferenza determina i tipi degli argomenti e, se disponibile, il tipo a cui viene assegnato o restituito il risultato. Infine, l'algoritmo di inferenza tenta di trovare il tipo più specifico che funzioni con tutti gli argomenti.

Due esempi su come funziona l'inferenza:

static <T> T pick(T a1, T a2) { return a2; } 
Serializable s = pick("d", new ArrayList<String>()); 

Il tipo T costituirebbero dunque come Serializable in base al tipo cessionario dichiarato.

public static <U> void addBox(U u, java.util.List<Box<U>> boxes) {} 
BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes); 

Il tipo U si inferisce come Integer base al tipo dell'argomento passato (cioè., Integer.valueOf(10) è di tipo Integer). Pertanto, <Integer> può essere omesso in sicurezza dall'invocazione del metodo di cui sopra.

Per riepilogare, a meno che non si sia in grado di dedurre il parametro di tipo del metodo generico dal tipo di argomento o il tipo di assegnazione o restituzione del risultato (durante il richiamo del metodo), è possibile omettere in modo sicuro la specifica del tipo proprio prima dell'invocazione del metodo.