拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Java中==和equals()的区别

Java中==和equals()的区别

白鹭 - 2022-05-15 2191 0 2

一、概述

在本教程中,我们将描述Java 中的两个基本相等检查——引用相等和值相等。我们将比较它们,展示示例,并突出它们之间的主要区别。

此外,我们将专注于null检查,并理解为什么在处理对象时应该使用引用相等而不是值相等。

2. 引用相等

我们将从理解引用比较开始,它由相等运算符( ==) 表示。当两个引用指向内存中的同一个对象时,就会发生引用相等

2.1 基本类型的比较

我们知道Java 中的原始类型是简单的、非类的原始值。当我们对原始类型使用相等运算符时,我们只是比较它们的值:

 int a = 10;
 int b = 15;
 assertFalse(a == b);

 int c = 10;
 assertTrue(a == c);

 int d = a;
 assertTrue(a == d);

如上所示,对于原语,相等性和引用检查的工作方式相同当我们用相同的值初始化一个新的原语时,检查返回true.此外,如果我们将原始值重新分配给新变量并进行比较,则运算符返回相同的结果。

现在让我们执行null检查:

 int e = null; // compilation error
 assertFalse(10 == null); // compilation error
 assertFalse(a == null); // compilation error

Java 禁止将null分配给原语。通常,我们不能使用相等运算符对原始变量或值执行任何null检查

2.2.对像类型的相等比较

对于Java 中的对像类型,相等运算符只执行引用相等比较,而忽略对象值。在我们实现测试之前,让我们创建一个简单的自定义类:

public class Person {
 private String name;
 private int age;

 // constructor, getters, setters...
 }

现在,让我们初始化一些类对象并检查相等运算符的结果:

Person a = new Person("Bob", 20);
 Person b = new Person("Mike", 40);
 assertFalse(a == b);

 Person c = new Person("Bob", 20);
 assertFalse(a == c);

 Person d = a;
 assertTrue(a == d);

结果与以前大不相同。第二次检查返回false,而我们为原语得到了true正如我们前面提到的,相等运算符在比较时忽略了对象的内部值。它只检查两个变量是否引用了相同的内存地址

与原语不同,我们可以在处理对象时使用null

assertFalse(a == null); Person e = null; assertTrue(e == null);

通过使用相等运算符并比较null,我们检查分配给变量的对像是否已经初始化

3.相同的值比较

现在让我们关注价值平等测试。当两个独立的对象碰巧具有相同的值或状态时,就会发生值相等

这会比较值,并且与Object's equals()方法密切相关。和以前一样,让我们将其与原语和对像类型的使用进行比较,看看关键的区别。

3.1 具有原始类型的equals()方法

众所周知,原语是具有单个值的基本类型,不实现任何方法。因此,不可能直接使用原语调用equals()方法

int a = 10; assertTrue(a.equals(10)); // compilation error

然而,由于每个原语都有自己的包装类,我们可以使用boxing mechanism将其转换为它的对象表示。然后,我们可以像使用对像类型一样轻松调用equals()方法:

 int a = 10;
 Integer b = a;

 assertTrue(b.equals(10));

3.2 具有对像类型equals()方法

让我们回到我们的Person类。为了让equals()方法正常工作,我们需要通过考虑类中包含的字段来覆盖自定义类中的方法:

public class Person {
 // other fields and methods omitted

 @Override
 public boolean equals(Object o) {
 if (this == o)
 return true;
 if (o == null || getClass() != o.getClass())
 return false;
 Person person = (Person) o;
 return age == person.age && Objects.equals(name, person.name);
 }
 }

首先,如果给定值具有相同的引用,equals()方法返回true,这由引用运算符检查。如果不是,我们开始平等测试。

此外,我们测试两个值的Class对象的相等性。如果它们不同,我们返回false否则,我们继续检查是否相等。最后,我们返回分别比较每个属性的组合结果。

现在,让我们修改之前的测试并检查结果:

Person a = new Person("Bob", 20);
 Person b = new Person("Mike", 40);
 assertFalse(a.equals(b));

 Person c = new Person("Bob", 20);
 assertTrue(a.equals(c));

 Person d = a;
 assertTrue(a.equals(d));

正如我们所见,第二个检查返回true而不是引用相等。我们重写的equals()方法比较对象的内部值。

如果我们不重写equals()方法,则使用父类Object中的方法。由于Object.equals()方法只进行引用相等性检查,因此在比较Person对象时,行为可能不是我们所期望的。

虽然我们没有在上面展示hashCode()方法,但我们应该注意,每当我们覆盖equals()方法时,覆盖它是很重要的以确保这些方法之间的一致性。

4. 处理Null值

最后,让我们检查一下equals()方法如何处理null值:

Person a = new Person("Bob", 20);
 Person e = null;
 assertFalse(a.equals(e));
 assertThrows(NullPointerException.class, () -> e.equals(a));

当我们使用equals()方法对另一个对象进行检查时,我们会根据这些变量的顺序得到两个不同的结果。最后一条语句引发异常,因为我们在null引用上调用了equals()方法。要修复最后一条语句,我们应该首先调用相等运算符检查:

assertFalse(e != null && e.equals(a));

现在,条件的左侧返回false,使整个语句等于false,从而防止了NullPointerException被抛出。因此,我们必须记住首先检查我们调用equals()方法的值不是null,否则会导致烦人的错误。

此外,从Java 7 开始,我们可以使用null 安全的方法来执行相等检查:Objects#equals() static

assertFalse(Objects.equals(e, a));
 assertTrue(Objects.equals(null, e));

此辅助方法执行额外的检查以防止抛出NullPointerException,当两个参数都为null时返回true

5. 结论

在本文中,我们讨论了引用相等和值相等检查原始值和对象值。

为了测试引用相等性,我们使用==运算符。该运算符对原始值和对象的工作方式略有不同。当我们将相等运算符与基元一起使用时,它会比较值。另一方面,当我们将它与对像一起使用时,它会检查内存引用。通过将其与null值进行比较,我们只需检查对像是否已在内存中初始化。

为了在Java 中执行值相等测试,我们使用从Object继承的equals()方法。Primitives 是简单的非类值,所以这个方法不能在没有包装的情况下被调用。

我们还需要记住只在实例化对像上调用equals()方法。否则会抛出异常。为了防止这种情况发生,如果我们怀疑null值,我们应该使用==运算符检查该值。



标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *