Java中equals()方法的行为

11

请考虑以下Java代码:

    Object a = new Integer(2);
    Object b = new Integer(2);
    System.out.println(a.equals(b));

    Object x = new Object();
    Object y = new Object();
    System.out.println(x.equals(y));

第一个打印语句输出true,第二个输出false

如果这是一种有意的行为,那么这如何帮助Java编程?

如果这不是一种有意的行为,那么这是Java中的缺陷吗?

5个回答

32

我会带着保留态度回答你的问题,但你应该知道,如果问题的目的是让你学习,而你的解决方法是去问StackOverflow,那么你就会伤害自己。不过话说回来...

这种行为是有意的。

java.lang.Object默认的equals()方法比较的是内存地址,这意味着所有对象都彼此不同(只有两个引用指向同一个对象才会返回true)。

java.lang.Integer覆盖了equals()方法,使之比较Integer,因此两个表示数字2的不同的Integer将相等。如果你使用==运算符,那么对于这两种情况,你将得到false

在Java中的标准做法是重写equals()方法,使其在逻辑上相等的对象返回true,即使它们是在不同时刻创建的(甚至使用不同的参数创建)。如果没有一种方式可以询问“这两个东西是否表示相同的值?”,那么拥有表示数字的对象就没有什么用了。

顺便说一下,这是个离题的话题,Java实际上为小值保留了Integer对象的缓存。因此有时你可能会得到两个不同来源但==运算符都返回trueInteger对象。甚至可以写出对大整数和小整数表现不同的代码,而无需查看其整数值!


尽管我们有“==”运算符来检查内存地址的相等性,但为什么Object定义了一个方法来检查内存地址,然后让子类如Integer()重写它以在不同的方式中使用?! - siva636
@MISS_DUKE 因为你无法重写 ==。子类也不能真正使其以“不同的方式”使用 - 每个类都有一个期望,即对于该特定类,每个类将使其执行相同的逻辑操作。这是继承的原则:如果您有一个 makeSound() 方法,对于鸭子来说它会是“嘎嘎声”,对于牛来说它会是“哞哞声”,但总体上它会为实现的动物发出正确的声音。 - Borealid
这意味着有一些类没有覆盖原始的equals方法,我说得对吗?(如果我说得对,请举一个这样的类作为例子) :) - siva636
1
@MISS_DUKE 是的,有些类没有覆盖 equals() 方法。实际上,这是大多数类 - 如果你随机选择一个类,很可能它没有(比如 java.awt.Canvas - 什么定义两个不同的画布是“相同的”?)。 - Borealid
太好了,我明白了。谢谢你,Borealid。 - siva636

7

这是预期行为。

Object.equals()认为对象标识(即对象仅等于自身)是唯一可以用于通用对象的东西。

Integer重写该方法以依赖于整数值,因为具有相同值的两个整数对象在逻辑上是相等的。许多其他类也重写了equals(),因为它是标准API的核心机制,许多集合框架中的功能依赖于它。

你为什么会对这种行为感到困惑呢?大多数人只会被==运算符所困惑(它的工作方式类似于Object.equals())。


3
Java中的equals方法有一个特定的目的:它确定对象是否逻辑上相等,即它们的内容相同,在每个特定类的上下文中可能意味着什么。这与对象相同是不同的:两个不同的对象可以在逻辑上等价。
回到你的例子,ab是表示相同逻辑实体的不同对象 - 整数值2。它们模拟相同的概念 - 整数,具有相同值的整数彼此相同。因此,ab是相等的。
另一方面,xy对象并不代表相同的逻辑实体(实际上,它们不代表任何东西)。这就是为什么它们既不相同也不等效的原因。

0

当然,这是有意为之的。

在比较Integer对象时,如果它们的值相等(在您的情况下为1),equals返回true

如果应用于不同类型的Object对象,则返回false

x.equals(x)

将返回true


0

另请参见Object.equals() doc。顺便说一下,考虑使用Integer.valueOf(2)而不是new Integer(2),因为它可以减少内存占用。

最后有趣的一件事是Integer.valueOf(2)==Integer.valueOf(2)将返回true,但Integer.valueOf(2000)==Integer.valueOf(2000)将返回false,因为在第一种情况下,您将收到两个相同的Integer对象实例(背后有一个缓存),但在第二种情况下,缓存仅适用于-127至128之间的值。


你的回答和问题实际上没有关系。== 的结果是正常的,不是好笑的。== 操作符比较的是引用,与值无关。所以在处理数字时,我们应该使用 equals 或 compareTo 方法。 - Damian Leszczyński - Vash
1
这个有争议。但显然他不知道equals方法的确切目的。它通常会与'=='混淆,由于我们正在讨论整数,我认为了解一些奇怪的行为可能是相关的,并且有时'=='将输出与equals相同的结果,而有时则不会。 - Guillaume Polet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接