java - 从语义上比较不同类型的数字

时间:2015-01-13 12:42:53

标签: java numbers comparison comparator comparable

说我有三个数字:

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接口。

3 个答案:

答案 0 :(得分:2)

first answer完全正确的为什么你得到ClassCastException - Comparable接口是通用的,只能用于相同具体类型的对象。

可能还有其他方法可以解决您的问题:

基元及其对象包装

如果您确定所有数字都是基元(int, long, float, double)或表示基元(Integer, Long, Float, Double)的类的对象,那么您可以使用常规比较运算符,例如等同于n1.compareTo(n2);

int b = n1 > n2 ? 1 : (n1 < n2 ? -1 : 0);

Number

的子类

如果您确定所有变量属于扩展Number的类,即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的评论讨论时 - 我们注意到,如果比较两个DoubleNumber,使用BigDecimal作为BigInteger比较的基类可能会产生虚假的平等超出Double范围的数字(因此.doubleValue()会根据需要返回Double.POSITIVE_INFINITYDouble.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);
    }

<强> / EDIT

实施Comparable但不要延长Number

如果你甚至不能确定你的变量扩展了Number,并且你可能正在处理一个带有表示数字的类的变量,那么实现Comparable,但是不扩展Number,我相信你只能比较参数如果属于同一类。在这种情况下,这应该可行,但我无法想象用例:

    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);

答案 1 :(得分:0)

你无法用这种方式比较它们。 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;
}

答案 2 :(得分:0)

正如人们所提到的,你无法“按原样”比较它们,但你可以实现一个新的比较器,它将接收不同的可能值,并将知道如何处理它们。下面是一个可能的实现,你有不同的构造函数(每个可能的值 - 可能可以改进那个部分),它将给定的值转换为“基本”类型(在我的情况下是double) - 而compareTo方法可以处理所有支持的类型由不同的构造者。

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;
    }
}
}

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; } } }