代码之家  ›  专栏  ›  技术社区  ›  b_erb

比较两个普通数字的值

  •  50
  • b_erb  · 技术社区  · 14 年前

    我想比较变量,两种类型 T extends Number . 现在我想知道这两个变量中哪一个大于另一个或相等。不幸的是,我还不知道确切的类型,我只知道它是 java.lang.Number . 我该怎么做?

    编辑 :我使用 TreeSet S,它实际上与自然排序一起工作(当然它工作,所有子类 Number 实施 Comparable 除了atomicinteger和atomiclong)。因此,我将丢失重复的值。使用时 List S Collection.sort() 由于绑定不匹配,将不接受我的列表。非常不满意。

    11 回复  |  直到 6 年前
        1
  •  30
  •   gustafc    7 年前

    一个有效的(但脆弱的)解决方案是这样的:

    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 是的,但是 合同不要求)。

    编辑,七年后: 正如评论中指出的,有(至少?)三个特例 弦线 能够产生你需要考虑的:

        2
  •  30
  •   BennyBoy    12 年前

    这应该适用于所有扩展数字的类,并且可以与它们自己进行比较。通过添加&comparable,您可以删除所有类型检查,并在与sarmun answer比较时免费提供运行时类型检查和错误引发。

    class NumberComparator<T extends Number & Comparable> implements Comparator<T> {
    
        public int compare( T a, T b ) throws ClassCastException {
            return a.compareTo( b );
        }
    }
    
        3
  •  12
  •   Lii Martin Sansone - MiOEE    6 年前

    一个可能对你有用的解决方案是不使用 T extends Number 但与 T extends Number & Comparable . 此类型表示:“ T 只能设置为实现的类型 二者都 接口。”

    这允许您编写适用于所有可比较数字的代码。静态类型和优雅。

    这与Bennyboy提出的解决方案相同,但它适用于各种方法,不仅适用于Comparator类。

    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
    }
    
        4
  •  11
  •   Community Egal    7 年前

    在问了一个 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);
        }
    }
    
        5
  •  5
  •   kopper    14 年前

    最“泛型”的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%精确的方法。数字接口没有像exactValue()这样的方法转换为某种类型,能够完美地表示数字而不丢失任何信息。

    事实上,拥有这样完美的数字通常是不可能的——例如,用有限空间的任何算法表示数字pi都是不可能的。

        6
  •  2
  •   Sarmun    13 年前

    这应该适用于所有扩展数字的类,并且可以与它们自己进行比较。

    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
  •  2
  •   rolve Tomasz    12 年前
    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;
    } 
    
        8
  •  1
  •   Steven Mackenzie    14 年前

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

        9
  •  1
  •   b_erb    14 年前

    这个怎么样?当然不是很好,但它处理所有必要的案件提到。

    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!");
                }
    
            }
    
        }
    
        10
  •  0
  •   Roman    14 年前

    假设您有如下方法:

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

    这将适用于字节、短、整数、长和双精度。

    如果假定可以传递biginteger或bigdecimal或float和double的组合,则无法创建一个通用方法来比较所有这些类型的参数。

        11
  •  0
  •   Yaneeve    14 年前

    如果您的数字实例是 从未 原子(即原子整数),然后可以执行如下操作:

    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 S实现可比性

    编辑 :

    这是因为反思而付出的代价:我知道

    编辑2 :

    当然,这不适用于将小数与整数或其他类似的情况。

    编辑3 :

    这假定没有自定义定义的数字后代不实现可比较(谢谢@djclayworth)