为什么 java.lang.Number 不实现 Comparable?
有谁知道为什么java.lang.Number
没有实现Comparable
? 这意味着您无法使用 Collections.sort 对 Number 进行排序,这在我看来有点奇怪。
讨论后更新:
感谢所有有用的回复。 我最终做了关于这个主题的更多研究。
为什么 java.lang.Number 没有实现 Comparable 最简单的解释是源于对可变性的考虑。
稍微回顾一下,java.lang.Number
是 AtomicInteger
、AtomicLong
、BigDecimal
的抽象超类型>、BigInteger
、字节
、双精度
、浮点
、整数
、长
和短
。 在该列表中,AtomicInteger
和 AtomicLong
不实现 Comparable
。
经过深入研究,我发现在可变类型上实现 Comparable 并不是一个好习惯,因为对象可能在比较期间或之后发生变化,从而导致比较结果无用。 AtomicLong
和 AtomicInteger
都是可变的。 API 设计者深思熟虑,不让 Number
实现 Comparable
,因为它会限制未来子类型的实现。 事实上,AtomicLong
和 AtomicInteger
是在 java.lang.Number
最初实现之后很久才添加到 Java 1.5 中的。
除了可变性之外,这里可能还有其他考虑因素。 Number
中的 compareTo
实现必须将所有数值提升为 BigDecimal
,因为它能够容纳所有 Number
> 子类型。 我不太清楚这种提升对数学和表现的影响,但我的直觉发现这个解决方案很糟糕。
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.
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.
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
.
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.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
值得一提的是,下面的表达式:
总是
false
,这往往会在某些时候让每个人都陷入困境。 因此,您不仅无法比较任意Number
,甚至无法确定它们是否相等。此外,对于真正的原始类型(
float
、double
),确定两个值是否相等是很棘手的,并且必须在可接受的误差范围内完成。 尝试这样的代码:你会留下一些细微的差别。
那么回到使
Number
Comparable
的问题。 你会如何实施它? 使用诸如doubleValue()
之类的东西不会可靠地做到这一点。 请记住Number
子类型是:Byte
;短
;整数
;长
;原子整数
;AtomicLong
;浮动
;双
;大整数
; 和您能否编写一个可靠的
compareTo()
方法,该方法不会转化为一系列 if instanceof 语句?Number
实例只有六个可用方法:byteValue()
;shortValue()
;intValue()
;longValue()
;floatValue()
; 和所以我猜 Sun 做出了(合理的)决定:
Number
只能与它们自身的实例Comparable
。It's worth mentioning that the following expression:
is always
false
, which tends to trip everyone up at some point or another. So not only can you not compare arbitraryNumber
s but you can't even determine if they're equal or not.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: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 likedoubleValue()
wouldn't do it reliably. Remember theNumber
subtypes are:Byte
;Short
;Integer
;Long
;AtomicInteger
;AtomicLong
;Float
;Double
;BigInteger
; andBigDecimal
.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:byteValue()
;shortValue()
;intValue()
;longValue()
;floatValue()
; anddoubleValue()
.So I guess Sun made the (reasonable) decision that
Number
s were onlyComparable
to instances of themselves.有关答案,请参阅 Java bugparade bug 4414323。 您还可以从 comp 中找到讨论.lang.java.programmer
引用 Sun 对 2001 年错误报告的回应:
For the answer, see Java bugparade bug 4414323. You can also find a discussion from comp.lang.java.programmer
To quote from the Sun response to the bug report from 2001:
为了实现数量上的可比较,您必须为每个子类对编写代码。 相反,只允许子类实现可比较更容易。
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.
要尝试解决原始问题(对数字列表进行排序),一种选择是声明扩展 Number 并实现 Comparable 的泛型类型的列表。
就像是:
To try to solve the original problem (sort a list of numbers), an option is to declare the list of a generic type extending Number and implementing Comparable.
Something like:
很可能是因为比较数字的效率相当低——每个数字可以适合进行这种比较的唯一表示形式是 BigDecimal。
相反,Number 的非原子子类实现了 Comparable 本身。
原子比较是可变的,因此无法实现原子比较。
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.
Instead, non-atomic subclasses of Number implements Comparable itself.
Atomic ones are mutable, so can't implement an atomic comparison.
您可以使用 Transmorph 使用其 NumberComparator 类来比较数字。
You can use Transmorph to compare numbers using its NumberComparator class.
编写自己的比较器
Write your own Comparator
不同类型的数字没有标准比较。、TreeSet等。 或 Collections.sort(List, Comparator) 或 Arrays.sort(Number[], Comparator);
但是,您可以编写自己的比较器并使用它来创建 TreeMap
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);
为什么这是个坏主意?
:
另一种选择可能是声明类 Number 实现 Comparable,省略compareTo 实现,并在某些类(如 Integer)中实现它,而在其他类(如 AtomicInteger)中抛出 UnsupportedException。
why this would have been bad idea?
:
another option may have been to declare class Number implements Comparable, omit compareTo implementation, and implement it in some classes like Integer while throw UnsupportedException in others like AtomicInteger.
我的猜测是,通过不实现 Comparable,它可以为实现类来实现或不实现它提供更大的灵活性。 所有常见数字(Integer、Long、Double 等)都实现了 Comparable。 只要元素本身实现 Comparable,您仍然可以调用 Collections.sort。
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.
查看类层次结构。 Long、Integer 等包装类实现了 Comparable,即 Integer 可以与整数进行比较,long 可以与 long 进行比较,但不能混合使用它们。 至少在这个泛型范式中是这样。 我想这回答了你的问题“为什么”。
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'.
byte
(基元)是一个int
(基元)。 基元一次只有一个值。语言设计规则允许这样做。
字节
不是整数
。Byte
是一个Number
,Integer
是一个Number
。Number
对象可以同时拥有多个值。如果
Byte
是Integer
并且Integer
是Number
,您将在Integer
中使用哪一个值code>compareTo(Number number1, Number number2) 方法?byte
(primitive) is aint
(primitive). Primitives have only one value at a time.Language design rules allows this.
A
Byte
is not anInteger
.Byte
is aNumber
and anInteger
is aNumber
.Number
objects can have more than one value at the same time.If a
Byte
is anInteger
and anInteger
is aNumber
, Which one value will you use in thecompareTo(Number number1, Number number2)
method?