比较两个通用数字的值

我想比较variables,两个typesT extends Number 。 现在我想知道两个variables中的哪一个大于另一个或相等。 不幸的是,我不知道确切的types,我只知道它将是一个java.lang.Number的子types。 我怎样才能做到这一点?

编辑 :我尝试了另一种解决方法,使用TreeSet实际上与自然sorting(当然,它的工作,除AtomicInteger和AtomicLong除外Number实现Comparable所有子类)。 所以我会失去重复的价值。 当使用List s时, Collection.sort()由于绑定不匹配而不会接受我的列表。 非常不满意。

一个工作(但脆弱)的解决scheme是这样的:

 class NumberComparator implements Comparator<Number> { public int compare(Number a, Number b){ return new BigDecimal(a.toString()).compareTo(new BigDecimal(b.toString())); } } 

不过,它仍然不是很好,因为它依赖于toString返回BigDecimal (标准的Java Number类所能做的,但是Number合同不需要的)可parsing的值。

编辑,七年后:正如在评论中指出的,至less有toString可以产生的三个特殊情况,你需要考虑:

  • Infinity ,比任何东西都大,除了它本身是平等的
  • -Infinity ,除了本身是平等的
  • NaN ,这是非常多毛/不可能比较,因为所有与NaN比较都会导致false ,包括检查与自己的平等 。

这应该适用于扩展Number的所有类,并且可以自己比较。 通过添加&Comparable,您可以删除所有的types检查,并提供运行时types检查和错误抛出与Sarmun答案相比。

 class NumberComparator<T extends Number & Comparable> implements Comparator<T> { public int compare( T a, T b ) throws ClassCastException { return a.compareTo( b ); } } 

在问了一个类似的问题,并在这里研究答案之后,我想出了以下结论。 我认为它比gustafc给出的解决scheme更高效,更强大:

 public int compare(Number x, Number y) { if(isSpecial(x) || isSpecial(y)) return Double.compare(x.doubleValue(), y.doubleValue()); else return toBigDecimal(x).compareTo(toBigDecimal(y)); } private static boolean isSpecial(Number x) { boolean specialDouble = x instanceof Double && (Double.isNaN((Double) x) || Double.isInfinite((Double) x)); boolean specialFloat = x instanceof Float && (Float.isNaN((Float) x) || Float.isInfinite((Float) x)); return specialDouble || specialFloat; } private static BigDecimal toBigDecimal(Number number) { if(number instanceof BigDecimal) return (BigDecimal) number; if(number instanceof BigInteger) return new BigDecimal((BigInteger) number); if(number instanceof Byte || number instanceof Short || number instanceof Integer || number instanceof Long) return new BigDecimal(number.longValue()); if(number instanceof Float || number instanceof Double) return new BigDecimal(number.doubleValue()); try { return new BigDecimal(number.toString()); } catch(final NumberFormatException e) { throw new RuntimeException("The given number (\"" + number + "\" of class " + number.getClass().getName() + ") does not have a parsable string representation", e); } } 

一个可能适用于你的解决scheme是不用T extends Number而是用T extends Number & Comparable 。 这种types意味着:“ T只能被设置为实现两个接口的types”。

这使您可以编写适用于所有可比数字的代码。 静态types和优雅。

这与BennyBoy提出的解决scheme是一样的,但它适用于各种方法,而不仅仅是比较器。

 public static <T extends Number & Comparable<T>> void compfunc(T n1, T n2) { if (n1.compareTo(n2) > 0) System.out.println("n1 is bigger"); } public void test() { compfunc(2, 1); // Works with Integer. compfunc(2.0, 1.0); // And all other types that are subtypes of both Number and Comparable. compfunc(2, 1.0); // Compilation error! Different types. compfunc(new AtomicInteger(1), new AtomicInteger(2)); // Compilation error! Not subtype of Comparable } 

最“通用”的Java原始数字是双倍的,所以使用简单

 a.doubleValue() > b.doubleValue() 

在大多数情况下应该是足够的,但是在将数字转换为双倍时,这里存在一些微妙的问题。 例如,以下是BigInteger可能的情况:

  BigInteger a = new BigInteger("9999999999999992"); BigInteger b = new BigInteger("9999999999999991"); System.out.println(a.doubleValue() > b.doubleValue()); System.out.println(a.doubleValue() == b.doubleValue()); 

结果是:

 false true 

虽然我希望这是非常极端的情况下,这是可能的。 没有 – 没有通用的100%准确的方法。 Number接口没有方法像exactValue()转换为某种types,可以完美的方式表示数字而不会丢失任何信息。

实际上,如此完美的数字是不可能的 – 例如,使用有限空间的任何算术来表示数字Pi是不可能的。

这个如何? 绝对不好,但它处理所有必要的案件。

 public class SimpleNumberComparator implements Comparator<Number> { @Override public int compare(Number o1, Number o2) { if(o1 instanceof Short && o2 instanceof Short) { return ((Short) o1).compareTo((Short) o2); } else if(o1 instanceof Long && o2 instanceof Long) { return ((Long) o1).compareTo((Long) o2); } else if(o1 instanceof Integer && o2 instanceof Integer) { return ((Integer) o1).compareTo((Integer) o2); } else if(o1 instanceof Float && o2 instanceof Float) { return ((Float) o1).compareTo((Float) o2); } else if(o1 instanceof Double && o2 instanceof Double) { return ((Double) o1).compareTo((Double) o2); } else if(o1 instanceof Byte && o2 instanceof Byte) { return ((Byte) o1).compareTo((Byte) o2); } else if(o1 instanceof BigInteger && o2 instanceof BigInteger) { return ((BigInteger) o1).compareTo((BigInteger) o2); } else if(o1 instanceof BigDecimal && o2 instanceof BigDecimal) { return ((BigDecimal) o1).compareTo((BigDecimal) o2); } else { throw new RuntimeException("Ooopps!"); } } } 
 if(yourNumber instanceof Double) { boolean greaterThanOtherNumber = yourNumber.doubleValue() > otherNumber.doubleValue(); // [...] } 

注意: instanceof检查不一定需要 – 取决于你想如何比较它们。 你当然可以简单地使用.doubleValue() ,因为每个Number都应该提供这里列出的方法。

编辑 :如评论中所述,您将(总是)必须检查BigDecimal和朋友。 但是他们提供了一个.compareTo()方法:

 if(yourNumber instanceof BigDecimal && otherNumber instanceof BigDecimal) { boolean greaterThanOtherNumber = ((BigDecimal)yourNumber).compareTo((BigDecimal)otherNumber) > 0; } 

你可以简单地使用Number's doubleValue()方法来比较它们; 但是您可能会发现结果不够准确,无法满足您的需求。

这应该适用于扩展Number的所有类,并且可以自己比较。

 class NumberComparator<T extends Number> implements Comparator<T> { public int compare(T a, T b){ if (a instanceof Comparable) if (a.getClass().equals(b.getClass())) return ((Comparable<T>)a).compareTo(b); throw new UnsupportedOperationException(); } } 

假设你有一些方法:

 public <T extends Number> T max (T a, T b) { ... //return maximum of a and b } 

如果您知道只有整数,则可以将long和double作为parameter passing,那么您可以将方法签名更改为:

 public <T extends Number> T max(double a, double b) { return (T)Math.max (a, b); } 

这将适用于字节,短,整数,长和双。

如果您认为可以传递BigInteger或BigDecimal或float和double的混合,则不能创build一个通用方法来比较所有这些types的参数。

如果你的数字实例从来没有primefaces(即AtomicInteger),那么你可以做这样的事情:

 private Integer compare(Number n1, Number n2) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Class<? extends Number> n1Class = n1.getClass(); if (n1Class.isInstance(n2)) { Method compareTo = n1Class.getMethod("compareTo", n1Class); return (Integer) compareTo.invoke(n1, n2); } return -23; } 

这是因为所有的非primefacesNumber都是Comparable

编辑

这是昂贵的反思:我知道

编辑2

这当然不是一个你想比较小数的整数或一些这样的情况下…

编辑3

这假设没有自定义的Number的后代不能实现Comparable(谢谢@DJClayworth)