我想比较T extends Number
类型的变量。现在我想知道这两个变量中哪一个大于另一个或相等。不幸的是我还不知道确切的类型,我只知道它将是java.lang.Number
的子类型。我怎么能这样做?
编辑:我尝试了使用TreeSet
的另一种解决方法,它实际上使用自然排序(当然它可以工作,Number
的所有子类都实现Comparable
除了AtomicInteger和AtomicLong)。因此,我将丢失重复值。使用List
时,由于绑定不匹配,Collection.sort()
将无法接受我的列表。非常不满意。
答案 0 :(得分:31)
这适用于所有扩展Number的类,并且可以与自己比较。通过添加&与Sarmun回答相比,您可以删除所有类型检查并提供免费的运行时类型检查和错误抛出。
class NumberComparator<T extends Number & Comparable> implements Comparator<T> {
public int compare( T a, T b ) throws ClassCastException {
return a.compareTo( b );
}
}
答案 1 :(得分:30)
工作(但脆弱)的解决方案是这样的:
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
合同不要求)。
编辑,七年之后:正如评论中指出的那样,(至少?)有三个特殊情况toString
可以产生您需要考虑的事项:
Infinity
,大于一切,除了它本身相等-Infinity
,它少于一切,除了它本身相等NaN
,自all comparisons with NaN
result in false
, including checking equality with itself以来非常多毛/无法比较。答案 2 :(得分:13)
可能适合您的一个解决方案是不使用T extends Number
,而是使用T extends Number & Comparable
。此类型表示:“T
只能设置为实现接口的类型。”
这允许您编写适用于所有可比数字的代码。静态打字和优雅。
这与BennyBoy提出的解决方案相同,但它适用于各种方法,不仅适用于比较器类。
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
}
答案 3 :(得分:11)
在问similar question并在这里研究答案后,我想出了以下内容。我认为它比gustafc给出的解决方案更有效,更强大:
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);
}
}
答案 4 :(得分:5)
最“通用”的Java原语编号是double,因此只需使用
a.doubleValue() > b.doubleValue()
在大多数情况下,应该足够了,但是......在将数字转换为double时,这里存在微妙的问题。例如,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()这样的方法转换为某种类型,能够以完美的方式表示数字,而不会丢失任何信息。
实际上通常不可能具有这样的完美数字 - 例如,使用有限空间的任何算术表示数字Pi是不可能的。
答案 5 :(得分:2)
if(yourNumber instanceof Double) {
boolean greaterThanOtherNumber = yourNumber.doubleValue() > otherNumber.doubleValue();
// [...]
}
注意:不一定需要instanceof
检查 - 取决于您想要比较它们的具体程度。您当然可以始终使用.doubleValue()
,因为每个数字都应提供列出的方法here。
编辑:如评论中所述,您将(总是)必须检查BigDecimal和朋友。但它们提供.compareTo()
方法:
if(yourNumber instanceof BigDecimal && otherNumber instanceof BigDecimal) {
boolean greaterThanOtherNumber = ((BigDecimal)yourNumber).compareTo((BigDecimal)otherNumber) > 0;
}
答案 6 :(得分:2)
这适用于所有扩展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();
}
}
答案 7 :(得分:1)
您只需使用Number's doubleValue()
方法进行比较即可;但是,您可能会发现结果不够准确,无法满足您的需求。
答案 8 :(得分:1)
这个怎么样?绝对不好,但它处理所提到的所有必要案例。
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!");
}
}
}
答案 9 :(得分:0)
我们假设你有一些方法,如:
public <T extends Number> T max (T a, T b) {
...
//return maximum of a and b
}
如果您知道只有整数,long和double可以作为参数传递,那么您可以将方法签名更改为:
public <T extends Number> T max(double a, double b) {
return (T)Math.max (a, b);
}
这适用于byte,short,integer,long和double。
如果您认为可以传递BigInteger或BigDecimal或者浮点数和双精度混合,那么您无法创建一种常用方法来比较所有这些类型的参数。
答案 10 :(得分:0)
如果您的数字实例 从不 Atomic(即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;
}
这是因为所有非原子Number
都实现了Comparable
修改强>:
由于反思,这很昂贵:我知道
编辑2 :
这当然不会考虑你想要将小数与int或者某些类似的数据进行比较......
编辑3 :
这假设没有自定义的Number后代没有实现Comparable(感谢@DJClayworth)
答案 11 :(得分:0)
System.out.println(new BigDecimal(0.1d).toPlainString());
System.out.println(BigDecimal.valueOf(0.1d).toPlainString());
System.out.println(BigDecimal.valueOf(0.1f).toPlainString());
System.out.println(Float.valueOf(0.1f).toString());
System.out.println(Float.valueOf(0.1f).doubleValue());