2013-04-15 12 views
7

Diciamo che hanno un metodo come questo:Metodo Generics senza argomenti

static class Example 
{ 
    public static <N extends Number> Number getOddBits(N type) 
    { 
     if (type instanceof Byte) return (byte)0xAA; 
     else if (type instanceof Short) return (short)0xAAAA; 
     else if (type instanceof Integer) return 0xAAAAAAAA; 
     else if (type instanceof Float) return Float.intBitsToFloat(0xAAAAAAAA); 
     else if (type instanceof Long) return 0xAAAAAAAAAAAAAAAAL; 
     else if (type instanceof Double) return Double.longBitsToDouble(0xAAAAAAAAAAAAAAAAL); 
     throw new IllegalArgumentException(); 
    } 
} 

Le specifiche effettive del metodo non è veramente importante. Tuttavia, per chiamare questo metodo che usiamo:

Example.<Float>getOddBits(0f); 

La mia domanda è, è possibile scrivere un tale metodo senza parametri convenzionali. Senza sovraccaricare, e in definitiva senza boxe.

Idealmente invocato da:

Example.<Byte>getOddBits(); 
+3

suppongo non a causa della cancellazione, ma si potrebbe sbarazzarsi del parametro di istanza superfluo e utilizzare un oggetto di classe come parametro: 'getOddBits (Classe Clazz )'. Non penso che tu possa aggirare il pugilato in quanto il tipo di ritorno non è sufficiente per creare firme distinte, ad esempio 'byte getOddBits()' e 'int getOddBits()' potrebbe essere ambiguo. – Pyranja

+0

Ci potrebbero essere anche altre opzioni. Perché hai bisogno di fare questo? per il tuo esempio, con la restituzione di valori fondamentalmente statici potresti semplicemente usare un enum. Se c'è qualcosa di più specifico potrebbero esserci anche altre opzioni. Ad esempio, se si converte un numero in un altro modulo, è possibile creare un'interfaccia di conversione come con un metodo toBytes e fromBytes. quindi avere tutte le classi necessarie per implementarlo. Non sono sicuro che questo aiuti, se no, potresti fornire un esempio più specifico più vicino a quello che ti serve? –

+0

@JohnKane L'esempio era arbitrario, solo per dimostrare l'uso di un tipo di restituzione sottoclasse come specificato tramite un argomento nel modo più accurato possibile. Probabilmente avrei potuto andare con il vecchio 'foo-bar-baz', ma ho pensato che un esempio pratico sarebbe stato più adatto. – azz

risposta

1

Come un miglioramento al suggerimento di KennyTM, è possibile combinare un argomento di classe con metodi generici per restituire il tipo specializzato:

@SuppressWarnings("unchecked") 
public static <N extends Number> N getOddBits(Class<N> cls) { 
    Number out; 
    if (cls == Byte.class) { 
     out = (byte)0xAA; 
    } else if (cls == Short.class) { 
     out = (short)0xAAAA; 
    } else if (cls == Integer.class) { 
     out = 0xAAAAAAAA; 
    } else if (cls == Float.class) { 
     out = Float.intBitsToFloat(0xAAAAAAAA); 
    } else if (cls == Long.class) { 
     out = 0xAAAAAAAAAAAAAAAAL; 
    } else if (cls == Double.class) { 
     out = Double.longBitsToDouble(0xAAAAAAAAAAAAAAAAL); 
    } else { 
     throw new IllegalArgumentException(); 
    } 
    return (N)out; 
} 

Questo vi permetterà di assegnare i seguenti, e di evitare un cast su ogni invocazione:

float result = Example.getOddBits(Float.class); 
+0

Ho appena inviato una modifica per supportare anche i valori primitivi ('cls == Integer.classe || cls == int.class'). Questa è sicuramente la soluzione ottimale da una prospettiva di pulizia dell'invocazione. – azz

+0

(ovvero, 'int i = Example.getOddBits (int.class);') – azz

7

ne dite di semplicemente fare una .class?

public static Number getOddBits(Class<? extends Number> cls) 
{ 
    if (cls == Byte.class) { 
     return (byte)0xAA; 
    } else if (cls == Short.class) { 
     return (short)0xAAAA; 
    } else if (cls == Integer.class) { 
     return 0xAAAAAAAA; 
    } else if (cls == Float.class) { 
     return Float.intBitsToFloat(0xAAAAAAAA); 
    } else if (cls == Long.class) { 
     return 0xAAAAAAAAAAAAAAAAL; 
    } else if (cls == Double.class) { 
     return Double.longBitsToDouble(0xAAAAAAAAAAAAAAAAL); 
    } 
    throw new IllegalArgumentException(); 
} 

... 

Example.getOddBits(Float.class); 
+0

Che funziona sicuramente. Stavo davvero cercando di spingere i generici del metodo al massimo, ma suppongo che la cancellazione faccia uso di 'Esempio. getOddBits() 'impossibile. – azz

+0

È possibile combinare questo approccio con la firma del metodo generico per restituire un tipo specializzato: 'public static N getOddBits (Classe cls) {' – seanhodges

+0

Ho espanso il mio commento sopra a una nuova risposta. – seanhodges

0

Im non sicuro se questo vi aiuterà, ma ho usato in passato per la deserializzazione e restituendo un oggetto del tipo appropriato.

public <T> T deserialize(String xml){ 
    T object=null; 
    ... 
    //pull type information from method param 
    ... 
    return object=(T)type.newInstance(); //helper to instantiate class 
} 

Tuttavia, non sono del tutto sicuro di ciò che è necessario fare. Un modo più semplice e più semplice per ottenere ciò potrebbe essere quello di creare un'interfaccia di conversione per i tipi specifici di cui si ha bisogno e fare in modo che tutte le classi abbiano bisogno di usarla per implementarla. Quindi ciò che mai ti serve, potrebbe essere chiamato direttamente sull'oggetto stesso. per esempio:

inerface Convertor<T>{ 

    T convert(); 

    void set(T value); 

} 





class Something implements Converter<Long,ByteArray>{ 

    ... 

    public ByteArray convert(){...} 

    public void set(ByteArray value){...} 

} 
Problemi correlati