2010-10-13 14 views
10

Ich möchte ein Verfahren schaffen, die eine Zahl vergleicht, kann aber einen Eingang, die eine der Unterklassen der Nummer ist.Java Generics und die Anzahl Klasse

Ich habe zu tun dies in der folgenden Weise sehe ...

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

Ich brauche die tatsächliche primitiven, bevor ich den Vergleich durchführen kann, die Number-Klasse hat Methoden, um dies für jeden primitiven abzurufen aber Ich möchte einen sauberen Weg, den richtigen zu wählen.

Ist das möglich?

Prost

+0

Verwandte: [Java: Allgemein Methoden und Zahlen] (http://stackoverflow.com/questions/3850970/java-generic-methods-and-numbers). – BalusC

Antwort

4

Leider gibt es keine Möglichkeit, den Urtyp von dem Wrapper-Typ zu erhalten, ohne zu if/else Blöcke zurückgreifen.

Das Problem ist, dass es einfach nicht möglich sein, ein solches Verfahren in allgemeiner Weise zu implementieren. Hier sind einige scheinbar mögliche Ansätze, die man erwarten könnte in der Number-Klasse zu finden:

public abstract X getPrimitiveValue(); 

Dies wäre schön, nicht wahr? Aber es ist unmöglich. Es gibt keine möglichen X, die eine Abstraktion über int sein könnte, float, double usw.

public abstract Class<?> getCorrespondingPrimitiveClass(); 

Dies wird auch nicht helfen, weil es keine Möglichkeit gibt primitive Klassen zu instanziiert.

Das einzige, was Sie, dass ist für alle Arten tun können, ist die longValue() oder doubleValue() Methoden zu verwenden, aber entweder so, wie Sie Informationen zu verlieren, wenn Sie mit dem falschen Typ zu tun hat.

Also nein: die Java-Nummernhierarchie ist einfach nicht geeignet, solche Probleme auf generische Weise zu lösen.

0

in diesem Fall, dass Sie ein gewöhnliches Verfahren ohne Generika

können
+0

Also, wenn die Methode entweder ein Double oder eine ganze Zahl akzeptieren soll, würde ich dann zwei Methoden mit unterschiedlichen Signaturen benötigen oder fehlt mir etwas? –

+0

@Mr_R: Wenn Sie Java 5 verwenden, konvertiert Autoboxing das zu Double und Integer, die beide Number implementieren. –

+2

Nutzen Sie Polymorphie und bieten Sie einfach eine 'evaluate (Number)' Methode –

8

Die Number API eine saubere Art und Weise bietet nicht den Wert zu erhalten; Sie müssen instanceof verwenden. Eine Lösung besteht darin, die Werte in zwei Typen zu "falten": long und double. Auf diese Weise können Sie diesen Code verwenden:

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

Beachten Sie, dass dies nur für die Standard-Nummerntypen funktioniert, aber Number wird auch von vielen anderen Arten (AtomicInteger, BigDecimal) umgesetzt.

Wenn Sie alle Arten unterstützen wollen, ist ein Trick BigDecimal zu verwenden:

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

die immer funktionieren soll und gibt Ihnen das genaue Ergebnis.

2

Methoden mit <T extends Number> sind immer Schwierigkeiten, da man nicht wirklich etwas auf einer Anzahl tun kann (alle Operatoren sind für die Kinder definiert). Sie müssten entweder eine Tonne instanceof für jedes Kind von Number eingeben und diesen Fall behandeln, indem Sie auf den Subtype umlenken. Oder (besser glaube ich - das ist die Art und Weise Sun es tut) ist nur eine Methode für jeden Kind-Typen, möglicherweise Vorteil des Boxens Einnahme/Unboxing für Operatoren wie +, -,> usw., wo das möglich ist (alle Verpackungen, nicht für BigInteger/BigDecimal oder beliebige benutzerdefinierte Typen).

1

Wenn es wirklich nur um das Argument des gleichen Typs Parameter auf einen anderen Wert zu vergleichen, dann können Sie die folgende (nur in T x der Einfachheit halber hinzufügen) tun

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