【问题标题】:Comparing Integer values in Java, strange behavior比较Java中的整数值,奇怪的行为
【发布时间】:2012-04-17 14:59:57
【问题描述】:

跟我走..

Integer x = 23;
Integer y = 23;

if (x == y)
    System.out.println("what else");      // All is well as expected
else
    System.out.println("...");

虽然

Integer x = someObject.getIndex();
Integer y = someOtherObject.getSomeOtherIndex();

if (x == y)
    System.out.println("what else");  
else
    System.out.println("...");        // Prints this 

嗯...我尝试转换为 int

int x = someObject.getIndex();
int y = someOtherObject.getSomeOtherIndex()

if (x == y)       
    System.out.println("what else");   // works fine
else
    System.out.println("...");  

它们都是整数吗?

System.out.println(x.getClass().getName());              // java.lang.Integer
System.out.println(y.getClass().getName());              // java.lang.Integer
System.out.println(someObject.getIndex());               // java.lang.Integer
System.out.println(someOtherObject.getSomeOtherIndex()); // java.lang.Integer

你们怎么看?如何解释这样的事情?

【问题讨论】:

标签: java


【解决方案1】:

当您在两个整数上使用== 时,自动装箱听起来很时髦。

如果您使用equals() 方法,我会假设它在使用Integer 时可以正常工作?反正我猜是这样的。

你没有使用 java 1.4 还是什么?

【讨论】:

  • 其他答案准确地说明了为什么会发生这种情况:JVM 缓存小整数值。因此,当我比较 (new Integer (12) == new Integer (12)) [yields true] 时,JVM 会为该值 12 的两侧返回相同的缓存对象。因此,这些对象确实是相同的。对于较大的值,会独立创建新对象,但不会发生这种情况。
【解决方案2】:

要正确比较整数,您需要使用.equals() 或通过转换为int 或在它们上调用intValue() 来比较它们的原始值。

使用==检查两个整数是否相同的对象,而不是它们是否包含相同的数值

    Integer a = new Integer(1);
    Integer b = new Integer(1);

    System.out.println(a.equals(b));                  //true
    System.out.println((int)a == (int)b);             //true
    System.out.println(a.intValue() == b.intValue()); //true
    System.out.println(a == b);                       //false

编辑从 JLS 中说明 Jon 关于自动装箱的观点:

    Integer a = 1;
    Integer b = 1;
    System.out.println(a.equals(b));                  //true
    System.out.println((int)a == (int)b);             //true
    System.out.println(a.intValue() == b.intValue()); //true
    System.out.println(a == b);                       //true

对比:

    Integer a = 128;
    Integer b = 128;
    System.out.println(a.equals(b));                  //true
    System.out.println((int)a == (int)b);             //true
    System.out.println(a.intValue() == b.intValue()); //true
    System.out.println(a == b);                       //false

【讨论】:

    【解决方案3】:

    您正在比较 Integer 值,它们是引用。您将通过自动装箱提出这些参考。对于某些值(保证为 -128 到 127),JRE 维护Integer 对象的缓存。对于更高的值,它不会。来自section 5.1.7 of the JLS

    如果被装箱的值 p 是真、假、一个字节或 \u0000 到 \u007f 范围内的一个字符,或者一个介于 -128 和 127(包括)之间的 int 或短数字,则令 r1 和 r2 为p 的任意两次装箱转换的结果。 r1 == r2 总是如此。

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

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

    道德:当您对基础 int 值感兴趣时,不要比较 Integer 引用。使用.equals() 或先获取int 值。

    【讨论】:

    • @JAM:是的,要么转换为int,调用intValue() 并比较结果,要么调用equals()
    猜你喜欢
    • 2017-10-23
    • 1970-01-01
    • 2015-02-17
    • 2012-05-12
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多