为什么 java.lang.Number 不实现 Comparable?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/480632/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't java.lang.Number implement Comparable?
提问by Julien Chastang
Does anyone know why java.lang.Number
does not implement Comparable
? This means that you cannot sort Number
s with Collections.sort
which seems to me a little strange.
有谁知道为什么 java.lang.Number
不实施Comparable
?这意味着您无法对Number
s 进行排序,Collections.sort
这在我看来有点奇怪。
Post discussion update:
帖子讨论更新:
Thanks for all the helpful responses. I ended up doing some more research about this topic.
The simplest explanation for why java.lang.Number does not implement Comparable is rooted in mutability concerns.
对 java.lang.Number 不实现 Comparable 的最简单解释源于可变性问题。
For a bit of review, java.lang.Number
is the abstract super-type of AtomicInteger
, AtomicLong
, BigDecimal
, BigInteger
, Byte
, Double
, Float
, Integer
, Long
and Short
. On that list, AtomicInteger
and AtomicLong
to do not implement Comparable
.
稍微回顾一下,java.lang.Number
是AtomicInteger
, AtomicLong
, BigDecimal
, BigInteger
, Byte
, Double
, Float
, Integer
, Long
and的抽象超类型Short
。在该列表中,AtomicInteger
并且AtomicLong
不执行Comparable
.
Digging around, I discovered that it is not a good practice to implement Comparable
on mutable types because the objects can change during or after comparison rendering the result of the comparison useless. Both AtomicLong
and AtomicInteger
are mutable. The API designers had the forethought to not have Number
implement Comparable
because it would have constrained implementation of future subtypes. Indeed, AtomicLong
and AtomicInteger
were added in Java 1.5 long after java.lang.Number
was initially implemented.
仔细研究,我发现Comparable
在可变类型上实现不是一个好习惯,因为对象可能会在比较期间或之后发生变化,从而导致比较结果无用。这两个AtomicLong
和AtomicInteger
是可变的。API 设计者有先见之明,没有Number
实现,Comparable
因为它会限制未来子类型的实现。确实,AtomicLong
并且AtomicInteger
在java.lang.Number
最初实现之后很久才被添加到 Java 1.5 中。
Apart from mutability, there are probably other considerations here too. A compareTo
implementation in Number
would have to promote all numeric values to BigDecimal
because it is capable of accommodating all the Number
sub-types. The implication of that promotion in terms of mathematics and performance is a bit unclear to me, but my intuition finds that solution kludgy.
除了可变性之外,这里可能还有其他考虑因素。compareTo
in的实现Number
必须将所有数值提升到,BigDecimal
因为它能够容纳所有Number
子类型。这种提升在数学和表现方面的含义对我来说有点不清楚,但我的直觉发现该解决方案很笨拙。
采纳答案by cletus
It's worth mentioning that the following expression:
值得一提的是下面的表达式:
new Long(10).equals(new Integer(10))
is always false
, which tends to trip everyone up at some point or another. So not only can you not compare arbitrary Number
s but you can't even determine if they're equal or not.
is always false
,这往往会在某些时候绊倒每个人。因此,您不仅不能比较任意Number
s,而且您甚至无法确定它们是否相等。
Also, with the real primitive types (float
, double
), determining if two values are equal is tricky and has to be done within an acceptable margin of error. Try code like:
此外,对于真正的原始类型 ( float
, double
),确定两个值是否相等很棘手,必须在可接受的误差范围内完成。试试这样的代码:
double d1 = 1.0d;
double d2 = 0.0d;
for (int i=0; i<10; i++) {
d2 += 0.1d;
}
System.out.println(d2 - d1);
and you'll be left with some small difference.
你会留下一些小的差异。
So back to the issue of making Number
Comparable
. How would you implement it? Using something like doubleValue()
wouldn't do it reliably. Remember the Number
subtypes are:
所以回到制作的问题Number
Comparable
。你将如何实施它?使用类似的东西doubleValue()
不会可靠地做到这一点。记住Number
子类型是:
Byte
;Short
;Integer
;Long
;AtomicInteger
;AtomicLong
;Float
;Double
;BigInteger
; andBigDecimal
.
Byte
;Short
;Integer
;Long
;AtomicInteger
;AtomicLong
;Float
;Double
;BigInteger
; 和BigDecimal
.
Could you code a reliable compareTo()
method that doesn't devolve into a series of if instanceof statements? Number
instances only have six methods available to them:
你能编写一个可靠的compareTo()
方法,它不会演变成一系列 if instanceof 语句吗? Number
实例只有六种方法可供它们使用:
byteValue()
;shortValue()
;intValue()
;longValue()
;floatValue()
; anddoubleValue()
.
byteValue()
;shortValue()
;intValue()
;longValue()
;floatValue()
; 和doubleValue()
.
So I guess Sun made the (reasonable) decision that Number
s were only Comparable
to instances of themselves.
所以我猜 Sun 做出了(合理的)决定,即Number
s 只Comparable
针对他们自己的实例。
回答by Pete Kirkham
Very probably because it would be rather inefficient to compare numbers - the only representation into which every Number can fit to allow such comparison would be BigDecimal.
很可能是因为比较数字的效率相当低 - 每个数字都可以适合进行这种比较的唯一表示是 BigDecimal。
Instead, non-atomic subclasses of Number implements Comparable itself.
相反, Number 的非原子子类实现了 Comparable 本身。
Atomic ones are mutable, so can't implement an atomic comparison.
原子是可变的,所以不能实现原子比较。
回答by Steve Kuo
My guess is that by not implementing Comparable, it give more flexibility to implementing classes to implement it or not. All the common numbers (Integer, Long, Double, etc) do implement Comparable. You can still call Collections.sort as long as the elements themselves implement Comparable.
我的猜测是,通过不实现 Comparable,它为实现类来实现它或不实现它提供了更大的灵活性。所有常见的数字(Integer、Long、Double 等)都实现了 Comparable。只要元素本身实现 Comparable,您仍然可以调用 Collections.sort。
回答by z -
in order to implement comparable on number, you would have to write code for every subclass pair. Its easier instead to just allow subclasses to implement comparable.
为了实现数量上的可比性,您必须为每个子类对编写代码。相反,只允许子类实现可比较更容易。
回答by airportyh
Looking at the class hierarchy. Wrapper classes like Long, Integer, etc, implement Comparable, i.e. an Integer is comparable to an integer, and a long is comparable to a long, but you can't mix them. At least with this generics paradigm. Which I guess answers your question 'why'.
查看类层次结构。Long、Integer 等包装类实现了 Comparable,即一个 Integer 相当于一个整数,一个 long 相当于一个 long,但你不能混合使用它们。至少有了这个泛型范式。我猜这回答了你的问题“为什么”。
回答by Eddie
For the answer, see Java bugparade bug 4414323. You can also find a discussion from comp.lang.java.programmer
有关答案,请参阅 Java bugparade bug 4414323。您还可以从comp.lang.java.programmer 中找到讨论
To quote from the Sun response to the bug report from 2001:
引用 Sun 对 2001 年错误报告的回应:
All "numbers" are not comparable; comparable assumes a total ordering of numbers is possible. This is not even true of floating-point numbers; NaN (not a number) is neither less than, greater than, nor equal to any floating-point value, even itself. {Float, Double}.compare impose a total ordering different from the ordering of the floating-point "<" and "=" operators. Additionally, as currently implemented, the subclasses of Number are only comparable to other instances of the same class. There are other cases, like complex numbers, where no standard total ordering exists, although one could be defined. In short, whether or not a subclass of Number is comparable should be left as a decision for that subclass.
所有的“数字”都没有可比性;可比较假设数字的总排序是可能的。这甚至不适用于浮点数。NaN(不是数字)既不小于、大于也不等于任何浮点值,甚至是它本身。{Float, Double}.compare 强加了不同于浮点“<”和“=”运算符的排序的总排序。此外,按照目前的实现,Number 的子类只能与同一类的其他实例进行比较。还有其他情况,如复数,其中不存在标准的总排序,尽管可以定义一种。简而言之,Number 的子类是否具有可比性应该留给该子类来决定。
回答by l_39217_l
byte
(primitive) is a int
(primitive). Primitives have only one value at a time.
Language design rules allows this.
byte
(原始)是一个int
(原始)。原语一次只有一个值。
语言设计规则允许这样做。
int i = 255
// down cast primitive
(byte) i == -1
A Byte
is not an Integer
. Byte
is a Number
and an Integer
is a Number
. Number
objects can have more than one value at the same time.
AByte
不是Integer
. Byte
是 aNumber
并且 anInteger
是Number
。Number
对象可以同时具有多个值。
Integer iObject = new Integer(255);
System.out.println(iObject.intValue()); // 255
System.out.println(iObject.byteValue()); // -1
If a Byte
is an Integer
and an Integer
is a Number
, Which one value will you use in the compareTo(Number number1, Number number2)
method?
如果 aByte
是 anInteger
并且 anInteger
是 a Number
,您将在compareTo(Number number1, Number number2)
方法中使用哪个值?
回答by Peter Lawrey
there is no stardard comparison for Numbers of different types. However you can write your own Comparator and use it to create a TreeMap<Number, Object>, TreeSet<Number> or Collections.sort(List<Number>, Comparator) or Arrays.sort(Number[], Comparator);
不同类型的数字没有标准比较。但是,您可以编写自己的 Comparator 并使用它来创建 TreeMap<Number, Object>、TreeSet<Number> 或 Collections.sort(List<Number>, Comparator) 或 Arrays.sort(Number[], Comparator);
回答by cchabanois
You can use Transmorphto compare numbers using its NumberComparator class.
您可以使用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);
回答by Hilmar
Write your own Comparator
编写自己的比较器
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() + ", ");
}
}
}