在scala.Any
的标量中,解释了运算符==
(或方法==
):
表达式
x == that
相当于if (x eq null) that eq null else x.equals(that)
http://www.scala-lang.org/api/current/#scala.Any
对于AnyRef
的子类的对象,我可以很容易地理解它,而且我没有看到任何奇怪的东西。
但是,对于AnyVal
的值,(我的意思是Int
,Double
,Long
等),上面的定义有些棘手({{1如果我们不将1 eq null
转换为java.lang.Integer,则不会编译。此外,1
和==
表现不同。
我会举一些例子。
scala> 1 == 1 res0: Boolean = true scala> 1 == 1.0 res1: Boolean = true scala> 1 == 1.2 res2: Boolean = false scala> 2 == BigInt(2) res3: Boolean = true scala> 2.0 == BigInt(2) res4: Boolean = true scala> 2 == BigInt(3) res5: Boolean = false
到目前为止,没有什么是奇怪的。但是,如果我们使用equals()
方法执行相同的操作,
scala> 1 equals 1 res7: Boolean = true scala> 1 equals 1.0 res8: Boolean = false scala> 1 equals 1.2 res9: Boolean = false scala> 2 equals BigInt(2) res10: Boolean = false scala> 2.0 equals BigInt(2) res11: Boolean = false scala> 2 equals BigInt(3) res12: Boolean = false
因此,如果类型不同,则equals()始终返回false,而==如果它们转换为相同类型则表示它们表示相同的值。
对于equals()
的子类,方法AnyRef
和==
会返回相同的内容。
scala> BigInt(2) == 2 res25: Boolean = true scala> BigInt(2) == 2.0 res26: Boolean = true scala> BigInt(3) == 2 res27: Boolean = false scala> BigInt(2) equals 2 res28: Boolean = true scala> BigInt(2) equals 2.0 res29: Boolean = true scala> BigInt(3) equals 2 res30: Boolean = false
那么,为什么方法equals()
和==
对equals()
不同?
我正在使用Scala版本2.10.2(Java HotSpot(TM)64位服务器VM,Java 1.7.0_25)。
编辑1
我看到==不能直接覆盖,因为根据Programming in Scala, 2nd Edition定义为Any类中的final方法。
编辑2
虽然有答案,但我的问题仍然存在。我会打开这个问题
与Java中的AnyVal
和scala.Int
对应的是Java的原始类型scala.Long
和int
。
在Java中,long
和java.lang.Integer
是类,因此它们的变量是引用,可以有java.lang.Long
。
这意味着,它们就像Scala中的null
一样。不是AnyRef
。
Scala的AnyVal
- AnyVal
和scala.Int
不能包含scala.Long
值,Java null
和int
也不能。{
此外,Java中的long
java.lang.Integer
用于引用相等(与Scala中的==
相同)。
在Scala REPL中使用eq
所获得的内容与使用.java源文件的纯Java项目中的内容完全不同。
但是,我在Java中使用原始类型的类可以得到:(这是JAVA)
java.lang.Integer
输出:
true false false true false是的,它们的行为类似于scala AnyVal的
class Main {
public static void main(String[] args) {
System.out.println(String.valueOf(new java.lang.Integer(1).equals(1)));
System.out.println(String.valueOf(new java.lang.Integer(1).equals(1L)));
System.out.println(String.valueOf(new java.lang.Integer(1).equals(1.0)));
System.out.println(String.valueOf(new java.lang.Integer(1).equals(new java.lang.Integer(1))));
System.out.println(String.valueOf(new java.lang.Integer(1).equals(new java.lang.Long(1))));
}
}
。但是,那么,为什么会发生这种情况呢?
Scala的equals()
的{{1}}是否与Java的原始类型的AnyVal
相对应
并且Scala的AnyVal的==
是否对应于Java类类的==
?
使用BigInt进行相等测试怎么样? Java中没有相应的原始类型
问题仍然存在......
编辑3
我可以从scaladoc找到一些信息。 (http://www.scala-lang.org/api/current/index.html#scala.Int)
Shadowed Implicit Value Members 项目中的隐含信息,
我发现equals()
,equals()
,==
以及...,
已超载Char
Short
会调用隐式转化Float
,==
或int2double
。
而int2float
仅为int2long
定义,而它会调用隐式转化equals()
。
也就是说,Any
将与int2Integer
相同
还有一个问题:
为什么Int.equals()
的{{1}}被重载,而java.lang.Integer.equals()
的{{1}}没有超载?
答案 0 :(得分:11)
相关讨论是描述性的
和推测
FWIW,规范调用了数值类型in 12.2的相等性。
或者,in HTML。 (在下面的底部引用。)
在2010年的“pidgin spec-ese”中,Paul Phillips这样说道:
比较两个基元(盒装或未装箱)和==应该总是给出 通过将这些值比较为未装箱的结果 原语。当你直接调用equals时,你正在跳过这一切 软化逻辑,而不是处理java的理论,两个盒装 不同类型的价值总是不相等。
规范没有提到盒装基元,除了在12.5中传递参考Predef
提供的转换。您通常不会意识到原语以“盒装”形式存储的时间,除非您出于性能原因需要这样做。
因此,例如,这些值将被静默地取消装箱并为您提升:
scala> val ds = List(7.0)
ds: List[Double] = List(7.0)
scala> val is = List(7)
is: List[Int] = List(7)
scala> ds(0) == is(0)
res24: Boolean = true
scala> :javap -
Size 1181 bytes
MD5 checksum ca732fd4aabb301f3ffe0e466164ed50
Compiled from "<console>"
[snip]
9: getstatic #26 // Field .MODULE$:L;
12: invokevirtual #30 // Method .ds:()Lscala/collection/immutable/List;
15: iconst_0
16: invokevirtual #36 // Method scala/collection/immutable/List.apply:(I)Ljava/lang/Object;
19: invokestatic #42 // Method scala/runtime/BoxesRunTime.unboxToDouble:(Ljava/lang/Object;)D
22: getstatic #47 // Field .MODULE$:L;
25: invokevirtual #50 // Method .is:()Lscala/collection/immutable/List;
28: iconst_0
29: invokevirtual #36 // Method scala/collection/immutable/List.apply:(I)Ljava/lang/Object;
32: invokestatic #54 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
35: i2d
36: dcmpl
你注意到我有点惊讶
2.0 == BigInt(2) // So far, nothing is strange.
对我而言,这有点神奇。如Paul Phillips所述,它会调用BoxesRunTime.equals
。
9: ldc2_w #22 // double 2.0d
12: invokestatic #29 // Method scala/runtime/BoxesRunTime.boxToDouble:(D)Ljava/lang/Double;
15: getstatic #34 // Field scala/package$.MODULE$:Lscala/package$;
18: invokevirtual #38 // Method scala/package$.BigInt:()Lscala/math/BigInt$;
21: iconst_2
22: invokevirtual #44 // Method scala/math/BigInt$.apply:(I)Lscala/math/BigInt;
25: invokestatic #48 // Method scala/runtime/BoxesRunTime.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z
这是规范,供参考,在这种形式基本上只承诺做正确的事情:
equals方法测试参数是否为数值类型。 如果这是真的,它将执行适当的==操作 对于那种类型。也就是说,数值类型的equals方法可以 被认为定义如下:
def equals(other: Any): Boolean = other match {
case that: Byte => this == that
case that: Short => this == that
case that: Char => this == that
case that: Int => this == that
case that: Long => this == that
case that: Float => this == that
case that: Double => this == that
case _ => false
}
答案 1 :(得分:2)
我希望这是因为自动装箱以及希望与Java保持的期望保持一致,以及在数据中的数学(1 = 1.0 = 1(表示为长)等)。例如,在Scala数字类型和Java数字类型之间运行比较:
scala> val foo: Long = 3L
foo: Long = 3
scala> val bar: Int = 3
bar: Int = 3
scala> foo == bar
res0: Boolean = true
scala> foo.equals(bar)
res1: Boolean = false
与:
相比scala> val jfoo = new java.lang.Long(3L)
jfoo: Long = 3
scala> val jbar = new java.lang.Integer(3)
jbar: Integer = 3
scala> jfoo == jbar
res2: Boolean = true
scala> jfoo.equals(jbar)
res3: Boolean = false