为什么这些==但不是`equals()`?

时间:2009-08-11 11:08:02

标签: java equals

当谈到==equals()和其他类型的数字时,我对Java处理intInteger的方式感到有些困惑。例如:

Integer X = 9000;
int x = 9000;
Short Y = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
// results.add(X == Y); DOES NOT COMPILE        1)
results.add(Y == 9000);                      // 2)
results.add(X == y);                         // 3)
results.add(X.equals(x));                    // 4)
results.add(X.equals(Y));                    // 5)
results.add(X.equals(y));                    // 6)
System.out.println(results);

输出(也许你应该先猜测):

[true, true, true, false, false]
  1. X == Y不能编译,是不同的对象。
  2. 我有点惊讶Y == 9true,因为默认情况下9是int,并且假设1甚至没有编译。请注意,您不能将int放入期望Short的方法中,但这里它们是相同的。
  3. 出于与两个相同的原因,这是令人惊讶的,但似乎更糟。
  4. 不足为奇,因为x已自动退回到Integer
  5. 不足为奇,因为不同类中的对象不应该是equal()
  6. 什么? X == ytrueX.equals(y)false==不应该比equals()更严格吗?
  7. 如果有人能帮助我理解这一点,我会很感激。出于什么原因,==和equals()会以这种方式运行?

    编辑:我已将9更改为9000,以表明此行为与-128到127之间的整数行为的任何异常方式无关。

    2 nd 编辑:好的,如果你认为你理解这些东西,你应该考虑以下几点,只是为了确保:

    Integer X = 9000;
    Integer Z = 9000;
    short y = 9000;
    List<Boolean> results = new ArrayList<Boolean>();
    results.add(X == Z);                      // 1)
    results.add(X == y);                      // 2)
    results.add(X.equals(Z));                 // 3)
    results.add(X.equals(y));                 // 4)
    System.out.println(results);
    

    输出:

    [false, true, true, false]
    

    原因,据我所知最好:

    1. 不同的实例,如此不同。
    2. X未装箱,然后是相同的值,如此相等。
    3. 相同的价值,如此平等。
    4. y无法装箱Integer,因此不能相等。

8 个答案:

答案 0 :(得分:21)

(小)整数实例被缓存,因此对于小实例(实际-127 +128,取决于JVM),不变的x == y被保留:

Integer a = 10;
Integer b = 10;

assert(a == b); // ok, same instance reused

a = 1024;
b = 1024;

assert(a == b); // fail, not the same instance....
assert(a.equals(b)); // but same _value_

修改

4)和5)产生错误,因为equals检查类型:X是整数,而Y是短。这是java.lang.Integer#equals方法:

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }

    return false;
}

答案 1 :(得分:11)

原因

X == y

为true与binary numeric promotion.有关当等于运算符的至少一个操作数可转换为数字类型时,使用numeric equality operator。首先,第一个操作数是未装箱的。然后,两个操作数都转换为int

虽然

X.equals(y)

是正常的函数调用。如上所述,y将自动装箱到Short个对象。如果参数不是Integer.equals实例,Integer总是返回false。通过检查实现可以很容易地看出这一点。

有人可能会说这是一个设计缺陷。

答案 2 :(得分:6)

故事的士气:

自动装箱/拆箱令人困惑,类型促销也是如此。他们共同创造了好的谜语,但却是可怕的代码。

实际上,使用小于int的数字类型很少有意义,而且我几乎倾向于配置我的eclipse编译器将所有自动装箱和-unboxing标记为错误。

答案 3 :(得分:3)

你的问题不仅仅是它如何对待==而是自动装箱......当你比较Y和9时,你正在比较两个相等的基元,在最后两种情况下你会得到假,因为这是等于工作的。只有两个对象具有相同的类型且具有相同的值时,它们才相等。 当您在“X.equals(y)”中说出你做Integer.equals(Short)并查看Integer.equals()的实现时它会失败:

   public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
    }

由于自动装箱,最后两个会导致同样的失败,因为它们都会作为短裤传递。

编辑:忘了一件事......在results.add(X == y)的情况下;它将unbox X和do(X.intValue()== y)恰好是真的以及9 == 9

答案 4 :(得分:1)

如果需要,Java会自动将Integer转换为int。同样适用于Short。此功能称为自动装箱和自动装箱。你可以阅读它here

这意味着当您运行代码时:

int a = 5;
Integer b = a;
System.out.println(a == b);

Java将其转换为:

int a = 5;
Integer b = new Integer(a);
System.out.println(a == b.valueOf());

答案 5 :(得分:1)

此自动转换称为自动装箱。

答案 6 :(得分:1)

我记得覆盖“equal(object obj)”的一个好习惯是首先检查传入的参数的类型。所以perhap这会导致 X.equals(Y)< / strong>要 false 。您可以查看源代码以挖掘真相:)

答案 7 :(得分:1)

关于自动装箱如何工作以及如何缓存“小”值Integer对象的更多细节:

当原始int被自动装入Integer时,编译器会通过调用Integer.valueOf(...)替换代码来完成此操作。所以,以下内容:

Integer a = 10;

由编译器替换为:

Integer a = Integer.valueOf(10);

类Integer的valueOf(...)方法维护一个缓存,该缓存包含介于-127和128之间的所有值的Integer对象。如果使用此范围内的值调用valueOf(...),则该方法返回缓存中预先存在的对象。如果该值超出范围,则返回使用指定值初始化的新Integer对象。 (如果您想确切知道它是如何工作的,请在JDK安装目录中查找文件 src.zip ,并在其中查找类java.lang.Integer的源代码。)

现在,如果你这样做:

Integer a = 10;
Integer b = 10;
System.out.println(a == b);

你会看到 true 被打印 - 但是不是因为a和b具有相同的值,但是因为a和b指的是同一个Integer对象, Integer.valueOf(...)返回的缓存中的对象。

如果更改值:

Integer a = 200;
Integer b = 200;
System.out.println(a == b);

然后打印 false ,因为200超出了缓存的范围,所以a和b引用了两个不同的Integer对象。

不幸的是,==用于值类型的对象相等,例如包装类和Java中的String - 这是违反直觉的。