为什么java.lang.Number没有实现Comparable?

时间:2009-01-26 17:32:53

标签: java sorting comparable

有谁知道为什么java.lang.Number没有实现Comparable?这意味着你无法用NumberCollections.sort进行排序,这对我来说有点奇怪。

发布讨论更新:

感谢所有有用的回复。我最终做了some more research about this topic

为什么java.lang.Number没有实现Comparable的最简单的解释源于可变性问题。

要进行一些审核,java.lang.NumberAtomicIntegerAtomicLongBigDecimalBigIntegerByte的抽象超类型,DoubleFloatIntegerLongShort。在该列表中,AtomicIntegerAtomicLong未实现Comparable

四处搜索,我发现在可变类型上实现Comparable并不是一个好习惯,因为对象可能会在比较期间或之后发生变化,导致比较结果无效。 AtomicLongAtomicInteger都是可变的。 API设计者已经考虑到没有Number实现Comparable,因为它会限制未来子类型的实现。实际上,AtomicLongAtomicInteger在最初实施java.lang.Number之后很久就在Java 1.5中添加了。

除了可变性之外,这里也可能有其他考虑因素。 compareTo中的Number实施必须将所有数值提升为BigDecimal,因为它能够容纳所有Number子类型。这个促销在数学和表现方面的含义对我来说有点不清楚,但我的直觉发现解决方案很难。

12 个答案:

答案 0 :(得分:63)

值得一提的是以下表达式:

new Long(10).equals(new Integer(10))

总是false,这往往会让某些人在某个时刻绊倒。因此,您不仅无法比较任意Number,而且甚至无法确定它们是否相等。

此外,对于真实的原始类型(floatdouble),确定两个值是否相等是棘手的,必须在可接受的误差范围内完成。尝试使用以下代码:

double d1 = 1.0d;
double d2 = 0.0d;
for (int i=0; i<10; i++) {
  d2 += 0.1d;
}
System.out.println(d2 - d1);

你会留下一些小小的差异。

回到制作Number Comparable的问题。你会如何实现它?使用像doubleValue()这样的东西不会可靠地做到这一点。请记住Number子类型是:

  • Byte;
  • Short;
  • Integer;
  • Long;
  • AtomicInteger;
  • AtomicLong;
  • Float;
  • Double;
  • BigInteger;和
  • BigDecimal

您是否可以编写一个可靠的compareTo()方法,该方法不会转换为一系列if instanceof语句? Number个实例只有六种可用的方法:

  • byteValue();
  • shortValue();
  • intValue();
  • longValue();
  • floatValue();和
  • doubleValue()

所以我猜Sun做出了NumberComparable对他们自己的实例的(合理的)决定。

答案 1 :(得分:42)

有关答案,请参阅Java bugparade bug 4414323。您还可以从comp.lang.java.programmer

中找到讨论

引用Sun对2001年错误报告的回应:

  

所有“数字”都不具有可比性;   可比较假设总排序   数字是可能的。这不是偶数   浮点数是真的;为NaN   (不是数字)既不低于,   大于,等于任何   浮点值,甚至本身。   {Float,Double} .compare总计   订购不同于订购   浮点数“&lt;”和“=”   运营商。此外,目前   实现,Number的子类   仅与其他实例相当   同一类。还有其他   案例,如复数,其中没有   存在标准总排序,   虽然可以定义一个。在   简而言之,无论是否为子类   数字可比较应保留为   对该子类的决定。

答案 2 :(得分:4)

为了实现数字的可比较,你必须为每个子类对编写代码。它更容易,只是允许子类实现可比较的。

答案 3 :(得分:3)

很可能因为比较数字效率相当低 - 每个数字可以容纳这种比较的唯一表示形式是BigDecimal。

相反,Number的非原子子类实现了Comparable本身。

原子可变,因此不能实现原子比较。

答案 4 :(得分:3)

您可以使用Transmorph使用其NumberComparator类比较数字。

NumberComparator numberComparator = new NumberComparator();
assertTrue(numberComparator.compare(12, 24) < 0);
assertTrue(numberComparator.compare((byte) 12, (long) 24) < 0);
assertTrue(numberComparator.compare((byte) 12, 24.0) < 0);
assertTrue(numberComparator.compare(25.0, 24.0) > 0);
assertTrue(numberComparator.compare((double) 25.0, (float) 24.0) > 0);
assertTrue(numberComparator.compare(new BigDecimal(25.0), (float) 24.0) > 0);

答案 5 :(得分:3)

要尝试解决原始问题(对数字列表进行排序),可以选择声明扩展Number并实现Comparable的泛型类型列表。

类似的东西:

<N extends Number & Comparable<N>> void processNumbers(List<N> numbers) {
    System.out.println("Unsorted: " + numbers);
    Collections.sort(numbers);
    System.out.println("  Sorted: " + numbers);
    // ...
}

void processIntegers() {
    processNumbers(Arrays.asList(7, 2, 5));
}

void processDoubles() {
    processNumbers(Arrays.asList(7.1, 2.4, 5.2));
}

答案 6 :(得分:1)

对于不同类型的数字没有标准比较。 但是,您可以编写自己的比较器并使用它来创建TreeMap&lt; Number,Object&gt;,TreeSet&lt; Number&gt;或Collections.sort(List&lt; Number&gt;,Comparator)或Arrays.sort(Number [],Comparator);

答案 7 :(得分:1)

编写自己的比较器

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class NumberComparator implements Comparator {
    @SuppressWarnings("unchecked")
    @Override
    public int compare(Number number1, Number number2) {
 if (((Object) number2).getClass().equals(((Object) number1).getClass())) {
     // both numbers are instances of the same type!
     if (number1 instanceof Comparable) {
  // and they implement the Comparable interface
  return ((Comparable) number1).compareTo(number2);
     }
 }
 // for all different Number types, let's check there double values
 if (number1.doubleValue() < number2.doubleValue())
     return -1;
 if (number1.doubleValue() > number2.doubleValue())
     return 1;
 return 0;
    }

    /**
     * DEMO: How to compare apples and oranges.
     */
    public static void main(String[] args) {
 ArrayList listToSort = new ArrayList();
 listToSort.add(new Long(10));
 listToSort.add(new Integer(1));
 listToSort.add(new Short((short) 14));
 listToSort.add(new Byte((byte) 10));
 listToSort.add(new Long(9));
 listToSort.add(new AtomicLong(2));
 listToSort.add(new Double(9.5));
 listToSort.add(new Double(9.0));
 listToSort.add(new Double(8.5));
 listToSort.add(new AtomicInteger(2));
 listToSort.add(new Long(11));
 listToSort.add(new Float(9));
 listToSort.add(new BigDecimal(3));
 listToSort.add(new BigInteger("12"));
 listToSort.add(new Long(8));
 System.out.println("unsorted: " + listToSort);
 Collections.sort(listToSort, new NumberComparator());
 System.out.println("sorted:   " + listToSort);
 System.out.print("Classes:  ");
 for (Number number : listToSort) {
     System.out.print(number.getClass().getSimpleName() + ", ");
 }
    }
}

答案 8 :(得分:1)

为什么这会是个坏主意? :

abstract class ImmutableNumber extends Number implements Comparable {
    // do NOT implement compareTo method; allowed because class is abstract
}
class Integer extends ImmutableNumber {
    // implement compareTo here
}
class Long extends ImmutableNumber {
    // implement compareTo here
}

另一个选项可能是声明类Number实现Comparable,省略compareTo实现,并在某些类(如Integer)中实现它,而在AtomicInteger等其他类中抛出UnsupportedException。

答案 9 :(得分:0)

我的猜测是,通过不实现Comparable,它可以更灵活地实现类来实现它。所有常用数字(Integer,Long,Double等)都实现了Comparable。只要元素本身实现Comparable,您仍然可以调用Collections.sort。

答案 10 :(得分:0)

查看类层次结构。像Long,Integer等包装类实现Comparable,即Integer与整数相当,long可以与long相比,但你不能混用它们。至少有这种泛型范例。我猜这回答你的问题'为什么'。

答案 11 :(得分:0)

byte(原始)是int(原始)。基元一次只有一个值 语言设计规则允许这样做。

int i = 255

// down cast primitive
(byte) i == -1

Byte不是IntegerByteNumberIntegerNumberNumber个对象可以同时拥有多个值。

Integer iObject = new Integer(255);
System.out.println(iObject.intValue());   // 255
System.out.println(iObject.byteValue());  // -1

如果ByteIntegerIntegerNumber,您将在compareTo(Number number1, Number number2)方法中使用哪一个值?