java中奇怪的等式行为

时间:2014-08-24 05:25:28

标签: java

看一下以下代码:

Long minima =          -9223372036854775808L;
        Long anotherminima =   -9223372036854775808L;
        System.out.println(minima==anotherminima); //evaluates to false
        System.out.println(Long.MIN_VALUE); 
        Long another= 1L;
        Long one = 1L;
        System.out.println(another == one); //evaluates to true

我无法理解这种行为..?我希望第一个eval也是真的.. 这就是我所期待的......

6 个答案:

答案 0 :(得分:4)

JVM使用一种缓存技术来处理某些范围的自动装箱值。如规范(http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7

中所述
  

如果装箱的值p为真,假,字节或范围为\ u0000到\ u007f的字符,或者介于-128和127(含)之间的整数或短数,则让r1和r2为p的任意两次拳击转换的结果。始终是r1 == r2。

的情况      

理想情况下,装箱给定的原始值p将始终产生相同的参考。实际上,使用现有的实现技术可能不可行。上述规则是一种务实的妥协。上面的最后一个条款要求将某些常见值装入无法区分的对象中。实现可以懒惰地或急切地缓存这些。对于其他值,此公式不允许对程序员的盒装值的身份进行任何假设。这将允许(但不要求)共享部分或全部这些引用。

     

这确保了在大多数情况下,行为将是所需的行为,而不会造成过度的性能损失,尤其是在小型设备上。例如,较少内存限制的实现可以缓存所有char和short值,以及-32K到+ 32K范围内的int和long值。

因此1L在此缓存值中,然后自动装箱提供完全相同的引用,但是在此范围之外的数字的情况下(如Long.MIN_VALUE),它不会被缓存,因此不同的实例/引用给出了。

在任何情况下,比较对象时都应该使用.equals()

答案 1 :(得分:2)

这里只是一个猜测,但可能是1L在常量池中,因此引用相等性的计算结果为true(就像有时候,甚至通过Strings,==将评估为true),而另一个巨大的号码不是。不知道如何在启动时检查池中的常量。

编辑:Java具有某些常量对象的缓存(包括基元的包装类和String)。因此,如果你写

String st1 = "A";

如果" A"在常量池中,Java不会创建新的String对象 - 它只会创建对现有String对象的引用。所以,如果你那么

String st2 = "A";
System.out.println(st1 == st2);

它会打印出来。

现在,并非所有Integer,Long,Short等都被缓存(有太多的东西),但是值越低。所以我认为1L是。这意味着在您的问题中,anotherone都引用同一个对象,因此即使引用相等也会返回true。

答案 2 :(得分:2)

首先,您应该使用long而不是Long。其次== Integer,Long等将检查引用相等性。您可以查看5.1.7 Boxing Conversion。 Alo 1L位于常量池中,因此第二种情况返回true。

在旁注中,您应该使用.equals来比较长。

来自Oracle文档:

  

如果框中的值p为true,false,则为字节或字符   范围\ u0000到\ u007f,或介于-128和127之间的int或短数字   (包括),然后让r1和r2成为任意两个拳击的结果   转换p。始终是r1 == r2。

的情况      

理想情况下,装箱给定的原始值p总会产生一个   相同的参考。在实践中,这可能是不可行的   现有的实施技术。上述规则是务实的   妥协。上面的最后一个条款要求某些共同的价值   总是被装入无法区分的物体。 [...]

     

这确保了在大多数情况下,行为将是   期望的,特别是没有施加过度的性能损失   在小型设备上。对于内存限制较少的实现可能   例如,缓存所有char和short值,以及int和long   值范围为-32K至+ 32K。

答案 3 :(得分:0)

<强>问题:

(minima==anotherminima)

您正在比较对象的内存位置而不是其值,因此返回 false

如果要比较两个长包装类,则需要调用compareTo

来自jls

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, 
or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results 
of any two boxing conversions of p. It is always the case that r1 == r2.

现在,如果你使用-128和127初始化Long包装器类,它将导致装箱转换,它具有相同的引用。

答案 4 :(得分:0)

添加到this answer,从-128到127的所有内容都缓存到永久java内存中的实例中,这意味着这些数字(几乎)总是具有引用相等性,因为不会为它们创建新实例。在缓存之外,每次使用该数字时都会创建一个新实例,因此它们在引用时不相等。 Read more herehere

答案 5 :(得分:-2)

您应该使用long代替Long。请注意,Long是一个类,因此您必须使用equals()来比较它的实例。另一方面,如果您使用long,则可以与==进行比较,因为这些是基元。