java - 从语义上比较不同类型的数字
java - comparing numbers of different type, semantically
假设我有三个号码:
Comparable n1 = new Integer(432);
Comparable n2 = new Long(40);
Comparable n3 = new Double(500.12);
我想通过Comparable
界面比较这些数字。但是,这会导致 ClassCastException
.
n1.compareTo(n2);
有没有办法(实用函数、外部库、...)来比较不同类型的数字?在上面的示例中,数字 n2
小于 n1
,并且 n1
小于 n3
,在语义上。
在代码中,我不知道数字的具体类型。因此,我依赖 Comparable
接口。
你不能那样比较它们。 Comparable 是一个通用接口,它只接受相同的类型。
您可以使用一种转换方法:
Comparable<Double> n1 = convertNumber(new Integer(432));
Comparable<Double> n2 = convertNumber(new Long(40));
Comparable<Double> n3 = convertNumber(new Double(500.12));
System.out.println(n1.compareTo(n2));
...
public Double convertNumber(Object o) {
if(o instanceof Double) {
return (Double)o;
} else if(o instanceof Long) {
return ((Long)o).doubleValue();
} else if(o instanceof Integer) {
return ((Integer)o).doubleValue();
}
return null;
}
完全正确地解释了为什么会出现 ClassCastException - Comparable 接口是通用的,只能用于相同具体类型的对象。
可能还有其他方法可以解决您的问题:
基元及其对象包装器
如果您确定所有数字都是基元 (int, long, float, double
) 或代表基元的 classes 的对象 (Integer, Long, Float, Double
),那么您可以使用普通比较运营商,例如相当于 n1.compareTo(n2);
int b = n1 > n2 ? 1 : (n1 < n2 ? -1 : 0);
class 属于 Number
如果您确定所有变量都是扩展 Number
的 Class,即 AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
,您可以使用以下内容:
private int compareNumbers(Number n1, Number n2)
{
Double n2c = n2.doubleValue();
Double n1c = n1.doubleValue();
return n1c.compareTo(n2c);
}
public static void main (String[] args)
{
Integer n1 = new Integer(432);
Long n2 = new Long(40);
Double n3 = new Double(500.12);
System.out.println(compareNumbers(n1,n2));
}
编辑
响应与 OP 的评论讨论 - 我们注意到,如果比较两个 BigDecimal
,使用 Double
作为 Number
比较的基础 class 可能会产生虚假的平等或 BigInteger
超出 Double
范围的数字(因此 .doubleValue()
returns Double.POSITIVE_INFINITY
或 Double.NEGATIVE_INFINITY
视情况而定)
如果这是一个问题,compareNumbers()
可以更改如下:
private int compareNumbers(Number n1, Number n2)
{
BigDecimal n2c = new BigDecimal(n2.toString());
BigDecimal n1c = new BigDecimal(n1.toString());
return n1c.compareTo(n2c);
}
/编辑
实施 Comparable
但不扩展 Number
如果您甚至不能确定您的变量是否扩展了 Number,并且您可能正在处理一个带有 class 表示数字的变量,实现 Comparable,但不扩展 Number,我相信您只能比较相同 class 的参数。在这种情况下,这应该可行,但我真的无法想象用例:
Comparable n1 = new WierdNonNumberExtendingInteger(432);
Comparable n2 = new WierdNonNumberExtendingLong(40);
Comparable n3 = new WierdNonNumberExtendingDouble(500.12);
Integer b = null;
if (n1.getClass().isInstance(n2))
{
b = n1.compareTo(n2);
}
else
{
System.err.println("Can't compare apples and oranges");
System.err.print("You tried to compare " + n1.getClass().getSimpleName());
System.err.print(" with " + n2.getClass().getSimpleName());
}
System.out.println(b);
正如人们提到的,您无法比较它们 "as-is",但您可以实现一个新的比较器,它将接收不同的可能值并知道如何处理它们。下面是一个可能的实现,其中你有不同的构造函数(每个可能的值 - 可能可以改进那部分)将给定值转换为 "base" 类型(在我的例子中是双精度) - 并且 compareTo 方法可以处理所有不同构造函数支持的类型。
</p>
<pre><code>public class MyTestClass
{
public static void main (String[] args) throws java.lang.Exception
{
MyComparator n1 = new MyComparator(new Integer(432));
MyComparator n2 = new MyComparator(new Long(40));
MyComparator n3 = new MyComparator(new Double(500.12));
}
static class MyComparator implements Comparable
{
double baseVal = 0.0d;
public double getValue() {
return baseVal;
}
public MyComparator(double d) {
this.baseVal = d;
}
public MyComparator(Long l) {
this.baseVal = l.doubleValue();
}
public MyComparator(int i) {
this.baseVal = (double)i;
}
public int compareTo(MyComparator toCompare) {
return ((Double)this.getValue()).compareTo(toCompare.getValue());
}
public int compareTo(Object o) {
// implemented only to support required interface methods
return 0;
}
}
}
假设我有三个号码:
Comparable n1 = new Integer(432);
Comparable n2 = new Long(40);
Comparable n3 = new Double(500.12);
我想通过Comparable
界面比较这些数字。但是,这会导致 ClassCastException
.
n1.compareTo(n2);
有没有办法(实用函数、外部库、...)来比较不同类型的数字?在上面的示例中,数字 n2
小于 n1
,并且 n1
小于 n3
,在语义上。
在代码中,我不知道数字的具体类型。因此,我依赖 Comparable
接口。
你不能那样比较它们。 Comparable 是一个通用接口,它只接受相同的类型。
您可以使用一种转换方法:
Comparable<Double> n1 = convertNumber(new Integer(432));
Comparable<Double> n2 = convertNumber(new Long(40));
Comparable<Double> n3 = convertNumber(new Double(500.12));
System.out.println(n1.compareTo(n2));
...
public Double convertNumber(Object o) {
if(o instanceof Double) {
return (Double)o;
} else if(o instanceof Long) {
return ((Long)o).doubleValue();
} else if(o instanceof Integer) {
return ((Integer)o).doubleValue();
}
return null;
}
可能还有其他方法可以解决您的问题:
基元及其对象包装器
如果您确定所有数字都是基元 (int, long, float, double
) 或代表基元的 classes 的对象 (Integer, Long, Float, Double
),那么您可以使用普通比较运营商,例如相当于 n1.compareTo(n2);
int b = n1 > n2 ? 1 : (n1 < n2 ? -1 : 0);
class 属于 Number
如果您确定所有变量都是扩展 Number
的 Class,即 AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
,您可以使用以下内容:
private int compareNumbers(Number n1, Number n2)
{
Double n2c = n2.doubleValue();
Double n1c = n1.doubleValue();
return n1c.compareTo(n2c);
}
public static void main (String[] args)
{
Integer n1 = new Integer(432);
Long n2 = new Long(40);
Double n3 = new Double(500.12);
System.out.println(compareNumbers(n1,n2));
}
编辑
响应与 OP 的评论讨论 - 我们注意到,如果比较两个 BigDecimal
,使用 Double
作为 Number
比较的基础 class 可能会产生虚假的平等或 BigInteger
超出 Double
范围的数字(因此 .doubleValue()
returns Double.POSITIVE_INFINITY
或 Double.NEGATIVE_INFINITY
视情况而定)
如果这是一个问题,compareNumbers()
可以更改如下:
private int compareNumbers(Number n1, Number n2)
{
BigDecimal n2c = new BigDecimal(n2.toString());
BigDecimal n1c = new BigDecimal(n1.toString());
return n1c.compareTo(n2c);
}
/编辑
实施 Comparable
但不扩展 Number
如果您甚至不能确定您的变量是否扩展了 Number,并且您可能正在处理一个带有 class 表示数字的变量,实现 Comparable,但不扩展 Number,我相信您只能比较相同 class 的参数。在这种情况下,这应该可行,但我真的无法想象用例:
Comparable n1 = new WierdNonNumberExtendingInteger(432);
Comparable n2 = new WierdNonNumberExtendingLong(40);
Comparable n3 = new WierdNonNumberExtendingDouble(500.12);
Integer b = null;
if (n1.getClass().isInstance(n2))
{
b = n1.compareTo(n2);
}
else
{
System.err.println("Can't compare apples and oranges");
System.err.print("You tried to compare " + n1.getClass().getSimpleName());
System.err.print(" with " + n2.getClass().getSimpleName());
}
System.out.println(b);
正如人们提到的,您无法比较它们 "as-is",但您可以实现一个新的比较器,它将接收不同的可能值并知道如何处理它们。下面是一个可能的实现,其中你有不同的构造函数(每个可能的值 - 可能可以改进那部分)将给定值转换为 "base" 类型(在我的例子中是双精度) - 并且 compareTo 方法可以处理所有不同构造函数支持的类型。
</p>
<pre><code>public class MyTestClass
{
public static void main (String[] args) throws java.lang.Exception
{
MyComparator n1 = new MyComparator(new Integer(432));
MyComparator n2 = new MyComparator(new Long(40));
MyComparator n3 = new MyComparator(new Double(500.12));
}
static class MyComparator implements Comparable
{
double baseVal = 0.0d;
public double getValue() {
return baseVal;
}
public MyComparator(double d) {
this.baseVal = d;
}
public MyComparator(Long l) {
this.baseVal = l.doubleValue();
}
public MyComparator(int i) {
this.baseVal = (double)i;
}
public int compareTo(MyComparator toCompare) {
return ((Double)this.getValue()).compareTo(toCompare.getValue());
}
public int compareTo(Object o) {
// implemented only to support required interface methods
return 0;
}
}
}