2013-02-27 28 views
8

In C++ è possibile specificare il tipo di ritorno di una funzione in un parametro, ad esempio:metodo con tipo di ritorno generico in Java

C++

float* myFloat = CollectionClass.ptr<float>(); 
    int* myInt = CollectionClass.ptr<int>(); 

Esiste un equivalente in Java per specificare il restituisce il tipo senza aggiungere ulteriori argomenti di classe?

Java

//This doesn't work (due to type erasure) 
    public <T> T getDate() 
    { 
     if (T instanceof Date) 
      return new Date(); 
     if (T instanceof Calendar) 
      return new Calendar(); 
    } 

    Date myDate = getDate<Date>(); 
+0

che cosa ti compri questo che non potresti realizzare semplicemente lanciando il ritorno più generico a una var più specifica? – amphibient

+1

ha aggiornato la domanda per essere più chiara – Jason

risposta

16

E 'perfettamente bene a dichiarare un metodo con la firma public <T> T getDate().

Tuttavia, è impossibile implementare il metodo che restituisce ciò che si desidera. Ciò che un metodo fa in runtime non può dipendere solo dal suo parametro type, perché non conosce il suo parametro type.

Per ottenere un'intuizione per questo, rendersi conto che qualsiasi codice scritto con generici può anche essere scritto in modo equivalente senza l'utilizzo di generici, semplicemente rimuovendo i parametri generici e inserendo i calchi laddove appropriato. Questo è ciò che significa "cancellazione di tipo".

Pertanto, per verificare se il metodo sarebbe possibile in Generics, semplicemente chiedere, come è possibile farlo senza Generics:

public Object getDate() 
{ 
    // what would you do here? 
} 

Date myDate = (Date)getDate(); 

Se non è possibile farlo senza Generics, non è possibile farlo con Anche i generici.

I modelli C++ sono completamente diversi. Per le funzioni e le classi basate su modelli, i modelli C++ generano una "copia separata" della funzione o della classe per ogni argomento di tipo che viene utilizzato con esso. il compilatore prende il codice basato su modello e lo "copia e incolla" in più versioni, ciascuna separata. Pertanto, ogni copia del codice è specifica per un determinato argomento di tipo e può quindi utilizzare quel tipo in fase di runtime.

Ecco perché è necessario che il codice di codice C++ sia disponibile in formato sorgente per poterlo utilizzare, non esistono modelli "compilati". Tuttavia, in Java, è possibile utilizzare una classe generica compilata. Classi e metodi generici in Java non assumono nulla sui tipi su cui possono essere utilizzati.

7

Okay, ora con la modifica per rendere chiaro che il codice è subordinata T ...

No, non c'è niente di semplice all'interno di Java per fare questo lavoro - a causa di tipo cancellato, come la tua domanda menziona. È possibile passare in Class<T>:

public <T> T getDate(Class<T> clazz) 
{ 
    // Now use clazz to work out what to do 
} 

... ma non si può fare nulla che dipende dal "valore" di T stessa in fase di esecuzione, in quanto questo è semplicemente non nota. Generics è un po 'anemica in Java, purtroppo :(


EDIT: Prima della modifica per rendere il codice condizionale sulla T ...

E' solo una questione di specificare l'argomento di tipo diverso:

import java.util.Date; 

class Test { 

    public static <T> T getDate() { 
     return (T) new Date(); 
    } 

    public <T> T getDateInstanceMethod() { 
     return (T) new Date(); 
    } 

    public static void main (String [] args) { 
     Date date = Test.<Date>getDate(); 

     // Compiles fine, but is obviously bogus. 
     String string = Test.<String>getDate(); 

     // And specifying a type argument for an instance method 
     Test test = new Test(); 
     date = test.<Date>getDate(); 
    } 
} 

ho sempre preferito l'approccio "mettere gli argomenti di tipo poco prima gli argomenti regolari" troppo, ma ci andiamo ...

E DIT: Come sottolinea rgettman, digitare inferenza farà la cosa giusta per te comunque qui, quindi in realtà non è necessario per specificare gli argomenti di tipo in molti casi. A volte lo fai però.

+0

Probabilmente vale la pena menzionare che a volte è possibile consentire al compilatore di dedurlo anche dalla destinazione, quindi 'Date date = Test.getDate();' funziona davvero bene nel codice sopra riportato. –

+0

quale sarebbe lo scopo di farlo in questo modo che non potreste fare se 'getDate' restituisse semplicemente Data? cosa ti compra l'uso dei generici in questo caso? – amphibient

+0

@foampile: Più di una domanda per Jason che Jon, non è vero? (Ma l'aggiornamento di Jason alla domanda chiarisce le cose ...) –

1

Con Arrays.asList, a volte è necessario specificare il tipo di reso. Java tenta di "restringere" il tipo restituito in base ai supertipi comuni di tutti gli argomenti, ma a volte è necessario un tipo specifico. Ad esempio,

List<Number> list = Arrays.asList(1, 2, 3); 

Qui, Arrays.asList restituisce un List<Integer> e si ottiene un errore di compilazione. Per farlo restituire un List<Number>, è necessario specificare il tipo generico.

List<Number> list = Arrays.<Number>asList(1, 2, 3); 
Problemi correlati