2010-10-13 10 views
10

Voglio creare un metodo che confronta un numero ma può avere un input che è una qualsiasi delle sottoclassi di Number.Generics Java e la classe Number

ho guardato a fare questo nel modo seguente ...

public static <T extends Number> void evaluate(T inputNumber) { 
    if (inputNumber >= x) { 
    ... 
    } 
} 

ho bisogno di ottenere la primitiva attuale prima di poter eseguire il confronto, la classe numero è metodi per recuperare questo per ogni primitiva, ma Voglio un modo pulito per selezionare quello corretto.

È possibile?

Acclamazioni

+0

correlate: [Java: metodi e numeri generici] (http://stackoverflow.com/questions/3850970/java-generic-methods-and-numbers). – BalusC

risposta

4

Sfortunatamente non c'è modo di ottenere il tipo primitivo dal tipo di wrapper senza ricorrere ai blocchi if/else.

Il problema è che semplicemente non sarebbe possibile implementare tale metodo in modo generico. Ecco alcuni apparentemente possibili approcci che ci si potrebbe aspettare di trovare nella classe Number:

public abstract X getPrimitiveValue(); 

Questo sarebbe bello, non è vero? Ma è impossibile. Non v'è alcuna possibilità X che potrebbe essere un'astrazione sopra int, float, double ecc

public abstract Class<?> getCorrespondingPrimitiveClass(); 

Questo non aiuterà neanche, perché non c'è modo di istanziare le classi primitive.

Quindi l'unica cosa che puoi fare è comune a tutti i tipi è usare i metodi longValue() o doubleValue(), ma in entrambi i casi perdi informazioni se hai a che fare con il tipo sbagliato.

Quindi no: la gerarchia dei numeri java non è adatta a risolvere tali problemi in modo generico.

0

in questo caso è possibile utilizzare un metodo ordinario senza farmaci generici

+0

Quindi, se il metodo deve accettare un numero doppio o un intero, mi occorrerebbero due metodi con firme diverse o mi manca qualcosa? –

+0

@Mr_R: se si utilizza Java 5, la funzione di autoboxing la convertirà in Double e Integer, entrambi implementano Number. –

+2

Approfitta del polimorfismo e offri semplicemente un metodo 'evaluate (Number)' –

8

Il Number API non offre un modo pulito per ottenere il valore; devi usare instanceof.

Una soluzione consiste nel "piegare" i valori in due tipi: long e double. In questo modo, è possibile utilizzare questo codice:

if(inputNumber instanceof Float || inputNumber instanceof Double) { 
    double val = inputNumber.doubleValue(); 
    ... 
} else { 
    long val = inputNumber.longValue(); 
    ... 
} 

Nota che questo funziona solo per i tipi di numero standard ma Number è implementata anche da un sacco di altri tipi (AtomicInteger, BigDecimal).

Se si desidera supportare tutti i tipi, un trucco è quello di utilizzare BigDecimal:

BigDecimal value = new BigDecimal(inputNumber.toString()); 

che dovrebbe sempre lavorare e dare il risultato più esatto.

2

I metodi con <T extends Number> sono sempre problemi, dal momento che non è possibile fare nulla su un numero (tutti gli operatori sono definiti per i bambini). Dovresti eseguire una tonnellata di instanceof per ogni figlio di Numero e trattare il caso eseguendo il casting sul sottotipo. Oppure (meglio penso - questo è il modo in cui lo fa Sun) è quello di avere un metodo per ogni tipo di bambino, magari approfittando del boxing/unboxing per operatori come +, -,> ecc. Dove è possibile (tutti i wrapper, non per BigInteger/BigDecimal o qualsiasi tipo personalizzato).

1

Se è davvero solo sul confronto l'argomento ad un altro valore dello stesso parametro di tipo allora si potrebbe procedere come segue (semplicemente aggiungendo in T x per semplicità)

public static <T extends Number & Comparable<? super Number>> int evaluate(T inputNumber, T x) { 
      if (inputNumber.compareTo(x) > 0) { ... } 
    }