2012-05-23 10 views
6

Creo una classe di preferenze e per i Getters non voglio usare token di tipo runtime.Ottieni istanza di Classe <T> [Token di tipo runtime]

Così qui è il mio metodo getter:

public <T> T get(String key, Class<T> clazz) { 
    // do some crazy stuff (e.g. Double <-> Float) 
} 

Fino a che, tutto funziona bene. Ma mi piacerebbe che il parametro di classe fosse opzionale.

boolean b = preferences.get(key); 

Così ho aggiungere un ulteriore metodo:

public <T> T get(String key) { 
    // return get(key, Class<T>); 
} 

Ora la domanda: C'è un modo per farlo? C'è un modo per ottenere un'istanza di Class<T>.

E 'possibile con una piccola soluzione:

public <T> T get(String key, T... args) { 
    return get(key, (Class<T>) args.getClass().getComponentType()); 
} 

public <T> T get(String key, Class<T> clazz) { 
    System.out.println("key : " + key); 
    System.out.println("clazz: " + clazz); 
} 

// using 
Boolean b = get("mykey"); 

risposta

3

È possibile con una piccola soluzione alternativa.

public <T> T get(String key, T... args) { 
    return get(key, (Class<T>) args.getClass().getComponentType()); 
} 

public <T> T get(String key, Class<T> clazz) { 
    System.out.println("key : " + key); 
    System.out.println("clazz: " + clazz); 
} 

// using 
Boolean b = get("mykey"); 

Jep Anche a me non piacciono i vararg, ma funziona così lontano.

+0

Cerca di non copiare e incollare la stessa risposta a più domande - se le domande stesse sono le stesse, considera invece di contrassegnarle come duplicate. Ho annullato questa risposta da quando hai rimosso l'altro. – BoltClock

+0

@BoltClock In realtà, ho accidentalmente postato la mia risposta in quell'altra domanda. Io ** ho cancellato immediatamente ** quello e l'ho postato qui. Quindi la mia risposta non esiste mai due volte. [JFYI] –

+0

Ah, capisco. A volte il sistema diventa schizzinoso sulle risposte incollate. Grazie per averlo chiarito! – BoltClock

3

Non è possibile. Ma se vuoi che il parametro class sia opzionale, passa semplicemente null e controlla se non è nullo quando lo usi.

Se si vuole inferirlo dal lato sinistro - non è possibile.

2

No. Le informazioni di tipo generico sono memorizzate nel metodo di chiamata, lo stesso T get(String key) compilato riconosce solo che è generico ma non ha modo di scoprire quale tipo di calcestruzzo è stato utilizzato per chiamarlo.

//code 
public <T> T get(String key) 
//calling code 
Integer value = get("value"); 

//once compiled 
public Object get(String key) 
//calling code 
Integer value = (Integer) get("value"); 
2

si può avere questo tipo di codice:

Integer i = getPref("integer"); 
System.out.println(i); 

@SuppressWarnings("unchecked") 
static <T> T getPref(String x) { 
    return (T)properties.get(x); 
} 

Qui, il tipo <T> è infatti dedotto dal lato sinistro. Tieni presente che ciò equivale solo ad aiutarti ad evitare un downcast esplicito a Integer - per me personalmente è sufficiente e uso spesso tali animali. Un altro punto da tenere presente è che l'inferenza di tipo di Java è piuttosto zoppa e non sarà possibile chiamare getPref come argomento per un altro metodo e avere il tipo di argomento inferito.

+0

Quindi i preferiti dell'App diventeranno le preferenze di Sistema! E non risolve il problema. Non puoi fondere un intero in un doppio! –

+1

@MarcelJaeschke Che cosa importa se utilizzo i pref di sistema come esempio? È più chiaro che inserire una variabile non dichiarata 'preferences' nel codice. E nulla può salvarti da un'eccezione di cast di classe se accedi al tipo sbagliato di preferenza. –

+0

E quando inferisce fallimenti puoi usare ' getPref (" foo ")' invece di creare un metodo addizionale per 'getPref (" foo ", Integer.class)' –

1

Non è possibile, ma ...

Invece di sovraccarico attraverso generici, considerare questo modello:

public boolean getBoolean(String key) { 
    // boolean impl here 
} 

public float getFloat(String key) { 
    // float impl here 
} 

// etc 

Non solo è più facile da codice, ma più facile da usare anche - almeno si sapere quali tipi sono accettabili.
Con il vostro codice attuale, questa sarebbe la compilazione:

SomeUnsupportedClass x = preferences.get("foo", SomeUnsupportedClass.class); 

ma che sarebbe esploso in fase di esecuzione, perché non hai il codice per sostenerlo.

A proposito, non va bene: vuoi rilevare problemi al momento della codifica, non al runtime.

+0

Penso che getWhatever() sia esattamente l'opposto di quello che viene menzionato. BTW: quando si riceve un errore se si usa getBoolean (chiave) {return (booleano) map.get (chiave)} e il valore è una stringa? –

+1

In fase di esecuzione, ma riceverai un'eccezione di una mancata corrispondenza di tipo, indipendentemente dal modello di codice che utilizzi. Ma quando conosci il tipo, puoi fare questo 'if (! (Valore instanceof Boolean)) lanciare IllegalArgumentException (" Value for '"+ key +' non è un booleano, ma è un" + value.getClass()) ; 'o simile a dare maggiori informazioni, o semplicemente restituire' null' senza esplodere se lo si desidera. – Bohemian

+0

Perché il downvote? – Bohemian

Problemi correlati