为什么这些==但不是`等于()`?(Why are these == but not `equals

2019-06-18 07:24发布

我关于Java对待的方式有点混乱==equals() ,当谈到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是autoboxed并Integer
  5. 并不奇怪,因为在不同的类的对象不应该是equal()
  6. 什么?? X == ytrue ,但X.equals(y)false ? 不宜==总是比严格equals()

我会很感激,如果有人能帮助我理解这一点。 是什么原因做==和equals()这样的行为?

编辑:我已经改变了9至9000表明,这种行为是不相关的任何不寻常的方式,该整数从-128到127的行为。

第二编辑:OK,如果你认为你明白这东西,你应该考虑以下内容,只是为了确保:

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 ,从而可以不相等。

Answer 1:

的原因

X == y

为真的有这样做的二进制数值提升。 当至少一个操作数的相等操作可以转换为一个数字类型, 数字相等运算被使用。 首先,第一个操作数拆箱。 然后,这两个操作数被转换为int

X.equals(y)

是一个普通的函数调用。 正如已经提到的, y将autoboxed一个Short的对象。 Integer.equals如果参数不是总是返回false Integer实例。 这可以通过检查落实情况很容易看到。

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



Answer 2:

(小)整数实例缓存,所以不变X == y的holded者为小实例(实际上-127 +128,取决于JVM):

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中的#等于方法:

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

    return false;
}


Answer 3:

这个故事的士气:

自动装箱/拆箱是混乱的,因为是类型提升。 总之,他们为好谜语,但可怕的代码。

在实践中,很少有意义的使用数值类型比INT小,我几乎倾向于配置我的Eclipse编译器标记所有自动装箱和-unboxing为错误。



Answer 4:

在这里你的问题不仅是如何对待==但自动装箱......当你比较Y和9你比较了两个基本要素是平等的,在后两种情况下,你得到错误的,只是因为这是如何工作的相等。 两个对象是仅当它们是同一种,并具有相同的值相等。 当您在“X.equals(Y)”你告诉它做Integer.equals(短),看着Integer.equals(实行说),它会失败:

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

由于自动装箱的最后两个将导致相同的故障,因为它们都将被传入的短裤。

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



Answer 5:

这种自动转换称为自动装箱。



Answer 6:

我记得重写“等于(obj对象)”一个好的做法是首先检查传入的参数的类型 。所以perhap这将导致X.equals(Y)假的 。 您可能要检查的烃源代码,以挖出真相:)



Answer 7:

如何自动装箱工作以及如何稍微详细的“小”有价值的Integer对象缓存:

当一个原始int值autoboxed成一个整数,所述编译器通过与到Integer.valueOf(...)的调用替代代码。 因此,以下内容:

Integer a = 10;

被替换通过与以下的编译器:

Integer a = Integer.valueOf(10);

调用valueOf(...)Integer类的方法维护一个包含-127和128之间的所有值Integer对象如果与在这一范围内的值调用的valueOf(...),该方法返回一个预先缓存从缓存中存在的对象。 如果该值在该范围之外,则返回与指定的值进行初始化一个新的整数对象。 (如果你想知道它究竟是如何工作的,查找文件src.zip在JDK安装目录,并查找类java.lang.Integer在它的源代码。)

现在,如果你这样做:

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

你会看到打印, 真正的 -但并不是因为A和B具有相同的价值,但由于A和B是指相同的Integer对象,从Integer.valueOf(...)返回缓存中的对象。

如果您更改值:

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

然后是印刷的,因为200是高速缓存的范围外,因此A和B指的是两个不同的整数对象。

这是不幸的==用于值类型对象的平等,如包装类和字符串在Java中 - 这是违反直觉的。



Answer 8:

Java将在需要时一个Integer自动转换成一个int。 同样适用于短。 此功能称为自动装箱和autounboxing。 你可以阅读一下这里 。

这意味着,当您运行的代码:

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());


文章来源: Why are these == but not `equals()`?
标签: java equals