为什么== operator和equals()对Scala中的AnyVal值的行为有所不同

Nae*_*mul 14 primitive scala equality equals

在scaladoc中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 eq null?如果我们不转变这并不编译1到java.lang.Integer中).此外,==equals()不同的表现.

我举几个例子.

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,而==如果它们转换为相同类型,则表示它们表示相同的值.

在子类的情况下AnyRef,方法==equals()返回相同.

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()不同AnyVal

我正在使用Scala版本2.10.2(Java HotSpot(TM)64位服务器VM,Java 1.7.0_25).

编辑1
我看到==不能直接覆盖,因为它被定义为类Any中的最终方法,根据Scala编程,第2版.

编辑2
虽然有答案,但我的问题仍然存在.我会打开这个问题.与Java

相对应的是Java的原始类型和. 在Java中,并且是类,因此它们的变量是引用,它们可以具有.这意味着,他们就像Scala一样.没有. Scala的- 并且不能有价值,Java 和Java也不能. 此外,的在Java是引用相等(相同Scala中). 在这方面,您在Scala REPL中使用的内容与使用.java源文件的纯Java项目中的内容完全不同. 但是,我在Java中使用原始类型的类可以得到:(这是JAVA)scala.Intscala.Longintlong
java.lang.Integerjava.lang.LongnullAnyRefAnyVal
AnyValscala.Intscala.Longnullintlong
java.lang.Integer==eq
java.lang.Integer

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))));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

true
false
false
true
false
是的,它们的行为类似于scala AnyVal equals().但是,那么,为什么会发生这种情况呢?

请问Scala的AnyVal==对应==Java的原始类型的
和不Scala的AnyVal的equals()对应于equals()Java的类类型的?
使用BigInt进行相等测试怎么样?Java中没有相应的原始类型.
问题仍然存在......

编辑3
我可以从scaladoc找到一些信息.(http://www.scala-lang.org/api/current/index.html#scala.Int)
隐含信息从该项目阴影内含价值会员,
我能找到==超载了Char,Short,Float,和... ,
并且==将调用隐式转换int2double,int2floatint2long.
equals()仅定义为Any,它将调用隐式转换int2Integer.
也就是说,Int.equals()将是一样的java.lang.Integer.equals().

还有一个问题:
为什么==AnyVal过载,并且equals()AnyVal不超载?

som*_*ytt 11

相关讨论是描述性的

从2010年开始==的规格

和投机的

从2011年开始重新考虑平等

FWIW,规范在12.2中调用数值类型的相等性.

或者,在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     
Run Code Online (Sandbox Code Playgroud)

你注意到我有点惊讶

2.0 == BigInt(2)  // So far, nothing is strange.
Run Code Online (Sandbox Code Playgroud)

对我来说,这有点神奇.它BoxesRunTime.equals如Paul Phillips所述.

     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
Run Code Online (Sandbox Code Playgroud)

这是规范,供参考,在这种形式基本上只承诺做正确的事情:

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
}
Run Code Online (Sandbox Code Playgroud)