Java 为什么JDK中的一些可比较类将比较函数限制为{−;1,0,1}和一些don';T
当Java 为什么JDK中的一些可比较类将比较函数限制为{−;1,0,1}和一些don';T,java,comparable,Java,Comparable,当ta和tb相等时,java.lang.Compariable接口明确要求的唯一返回值是0。如果a小于b,则比较(a,b)必须为负数,不一定为负数−1和比较(b,a)必须为正,而不一定为1 但JDK中的一些可比较类正是以这种方式限制比较函数的输出,例如 scala> (65 to 90).map(n => java.lang.Integer.compare(77, n)) res19: IndexedSeq[Int] = Vector(1, 1, 1, 1, 1, 1, 1, 1,
ta
和tb
相等时,java.lang.Compariable
接口明确要求的唯一返回值是0。如果a
小于b
,则比较(a,b)
必须为负数,不一定为负数−1和比较(b,a)
必须为正,而不一定为1
但JDK中的一些可比较类正是以这种方式限制比较函数的输出,例如
scala> (65 to 90).map(n => java.lang.Integer.compare(77, n))
res19: IndexedSeq[Int] = Vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
而有些则没有,例如
scala> ('A' to 'Z').map(ch => java.lang.Character.compare('M', ch))
res10: IndexedSeq[Int] = Vector(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13)
我很清楚RDN有点晦涩难懂(来自javax.naming.ldap
),但我没想到会在java.lang
中遇到这种情况。我首先注意到Java中Caesar cypher程序的Character.compare()
中的无限制输出,但我发现在本地Scala REPL中运行类似的“实验”更容易
当我编写分数
的实现时,我遵循了整数
的示例,而不是字符
scala> val fractA = new fractions.Fraction(65, 128)
fractA: fractions.Fraction = 65/128
scala> val fractB = new fractions.Fraction(90, 128)
fractB: fractions.Fraction = 45/64
scala> fractA to fractB
res20: fractions.FractionRange = 65/128 to 45/64
scala> val fractC = new fractions.Fraction(77, 128)
fractC: fractions.Fraction = 77/128
scala> res20.map(_.compare(fractC))
res21: IndexedSeq[Int] = Vector(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
scala> res20.map(fractC.compare)
res22: IndexedSeq[Int] = Vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
scala> res19 == res22
res23: Boolean = true
在分数的情况下,像这样实现它是没有问题的。事实上,不这样做会更麻烦。分子和分母的类型为long
,因此,如果差异的分子稍微超出int
的范围,则可能会出现问题。通过使用Long.signum()
,我将错误结果的可能性降低到一小部分边缘情况
由于char
映射到int
范围的一半,我认为String
更容易不将compare()
的结果限制为{−1,0,1}
scala> "Hello, World!" compare "Hello, world?"
res30: Int = -32
这里我猜测,如果没有涉及代理,或者即使涉及代理,也更容易在字符串的每个字符上运行Character.compare()
,直到第一个非零结果或到达末尾
这就是我们应该做最简单的事情并给出正确结果的解释吗?还是有更深层次的原因来限制某些可比类别的差异,而不是其他类别的差异?主要答案
因为实现可以自由选择最适合自己的正值或负值。返回值如下所示:
负整数、零或正整数,因为此对象较小
大于、等于或大于指定对象
有人可能会争论这个规范是否是一个明智的决定,但这就是它的定义方式。因此,永远不要依赖于比较结果仅为-1、0或1,即使使用一个特定的Java版本进行实验表明这种行为——它可能会随着下一个版本而改变
实现答案
这个答案主要已经在你的问题中找到了
有两种典型的比较方法:
- 整数减法:它给出的结果不限于-1、0、1。代码简单、优雅、快速。但也可能存在溢出,例如,对于值2_000_000_000-(-2_000_000_000)而言,数学上是4_000_000_000,但对于32位int,结果显示为-294_967_296,错误地暗示2_000_000小于-2_000_000。为了避免溢出,整数减法适用于大约+/-1_000_000_000的数字
- 决策:如果。。。否则如果。。。else
构造,其中明确给出了三种情况的返回值。那么使用-1、0和1是很自然的选择,我不知道有哪个实现使用了其他固定值
所以,减法是字节和字符的有效解决方案,其中基于int的减法有足够的保留位,不会发生溢出。因此,这些数据类型及其派生类型更有可能显示-1、0和1之外的值
分数类
你正在写一个你正在实现的分数类。如果可以创建两个分数实例,而不给出异常,我将要求compareTo()
方法始终给出正确的结果。由于分数的比较是一件棘手的事情,中间结果的溢出是可以预料的。因此,我建议创建一些分子和/或分母接近有效性限制的测试用例(无论您定义它们是什么)
另一种避免溢出的方法是切换到无限范围的biginger
类型,但这可能会影响性能。主要答案
因为实现可以自由选择最适合自己的正值或负值。返回值如下所示:
负整数、零或正整数,因为此对象较小
大于、等于或大于指定对象
有人可能会争论这个规范是否是一个明智的决定,但这就是它的定义方式。因此,永远不要依赖于比较结果仅为-1、0或1,即使使用一个特定的Java版本进行实验表明这种行为——它可能会随着下一个版本而改变
实现答案
这个答案主要已经在你的问题中找到了
有两种典型的比较方法:
- 整数减法:它给出的结果不限于-1、0、1。代码简单、优雅、快速。但也可能存在溢出,例如,对于值2_000_000_000-(-2_000_000_000)而言,数学上是4_000_000_000,但对于32位int,结果显示为-294_967_296,错误地暗示2_000_000小于-2_000_000。为了避免溢出,整数减法适用于大约+/-1_000_000_000的数字
- 决策:如果。。。否则如果。。。else
构造,其中明确给出了三种情况的返回值。那么使用-1、0和1是很自然的选择,我不知道有哪个实现使用了其他固定值
苏