比较两个通用数字的值
我想比较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)
- Android Studio TransformException:错误:任务执行失败':app:transformClassesWithDexForDebug'
- 问题parsing货币文本为十进制types