使用equals
和hashcode
比较java对象
equals
和hashcode
之间的关系是什么?当比较java对象时,如何使用这两个方法?
在这篇文章中,您将了解如何将equals()
和hashcode()
结合起来,使Java程序中的对象比较变得高效和简单。简单地说,将使用这些方法来验证两个对象是否具有相同的值。
如果没有equals()
和hashcode()
,我们将不得不使用非常多的if
进行比较,分别比较对象中的每个字段。这将使代码非常混乱和难以阅读。然而使用这两种方法将帮助我们创建更加灵活和良好的代码结构。
在java中重写 equals()
and hashcode()
方法
重载是为了使用多态而出现的一种技术:父类或接口的行为在子类中被重写(覆盖)。Java中的每个object
都包含一个equals()
和一个hashcode()
方法,但是必须重写它们才能正常使用。
为了理解如何使用equals()
和hashcode()
方法进行重载,我们可以在核心Java类中研究它们的实现。下面是object
类中的equals()
方法。该方法正在检查当前实例是否与先前传递的对象相同。
public boolean equals(Object obj) {
return (this == obj);
}
当hashcode()
方法未被重写时,将调用对象类中的默认方法。这是一个native
方法,这意味着它将以另一种语言(如C)执行,并将返回一些有关对象的内存地址。
@HotSpotIntrinsicCandidate
public native int hashCode();
当equals()
和hashcode()
方法没有被重写时,您将看到上面的方法被调用。在本例中,这些方法并没有实现equals()
和hashcode()
的真正目的,即检查两个或多个对象是否具有相同的值。
通常,当您重写equals()
时,还必须重写hashcode()
。
使用equals()
比较对象
我们使用equals()
方法来比较Java中的对象。为了确定两个对象是否相同,我们使用equals()
比较对象属性值。
public class EqualsAndHashCodeExample {
public static void main(String... equalsExplanation) {
System.out.println(new Simpson("Homer", 35, 120)
.equals(new Simpson("Homer",35,120)));
System.out.println(new Simpson("Bart", 10, 120)
.equals(new Simpson("El Barto", 10, 45)));
System.out.println(new Simpson("Lisa", 54, 60)
.equals(new Object()));
}
static class Simpson {
private String name;
private int age;
private int weight;
public Simpson(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Simpson simpson = (Simpson) o;
return age == simpson.age &&
weight == simpson.weight &&
name.equals(simpson.name);
}
}
}
在第一个比较中,equals()
将当前对象实例与已传递的对象进行比较。如果两个对象具有相同的值,则equals()
将返回true
。
在第二个比较中,equals()
检查传递的对象是否为null
,或者判断其类型是否相同。如果对象类型不同,那么对象则不相等。
最后,equals()
比较对象字段。如果两个对象具有相同的字段值,那么它们就是相同的。
代码分析
现在,让我们在main()方法中查看这些对象的比较结果。首先,我们比较两个Simpson对象:
System.out.println(new Simpson("Homer", 35, 120).equals(new Simpson("Homer", 35, 120)));
这里的对象是相同的,所以结果将为真。
接下来,我们再次比较两个Simpson对象:
System.out.println(new Simpson("Bart", 10, 45).equals(new Simpson("El Barto", 10, 45)));
这两个object
几乎一模一样,但它们的name
字段的值却不一样:Bart
和 ElBarto
。因此,结果将是false
。
最后,让我们比较一个Simpson
对象和一个类对象实例:
System.out.println(new Simpson("Lisa", 54, 60).equals(new Object()));
在这个案例中,由于对象类型不同,结果将为false
。
equals()
与 ==
区别
乍一看,==
操作符和equals()
方法似乎做了相同的事情,但实际上它们是两种不同的操作。操作符==
比较两个对象引用是否指向同一地址,即判断两个对象是不是同一个对象。例如
System.out.println(homer == homer2);
该代码中,我们使用new
操作符实例化了两个不同的Simpson
实例。因此,变量homer
和homer2
将指向内存堆中的不同对象引用。结果是false
。
System.out.println(homer.equals(homer2));
而这段代码中,我们重写了equals()
方法。在这种情况下,只比较names
。因为两个Simpson
对象的names
都是Homer
,所以结果将为true
。
使用 hashcode()
来辨别对象
在比较对象时,我们使用hashcode()
方法来优化性能。执行hashcode()
将为程序中的每个对象返回一个唯一ID
,这使得比较对象的整个状态变得更加容易。
如果一个对象的hashcode
与另一个对象的hashcode
不同,那么就没必要执行equals()
方法:因为你可以通过hashcode
得知这两个对象并不相同。另一方面,如果hashcode
相同,那么就有必要执行equals()
方法来确定这两个对象的所有字段值是否相同。
这里有一个hashcode()
的实际例子:
public class HashcodeConcept {
public static void main(String... hashcodeExample) {
Simpson homer = new Simpson(1, "Homer");
Simpson bart = new Simpson(2, "Homer");
boolean isHashcodeEquals = homer.hashCode() == bart.hashCode();
if (isHashcodeEquals) {
System.out.println("Should compare with equals method too.");
} else {
System.out.println("Should not compare with equals method because " +
"the id is different, that means the objects are not equals for sure.");
}
}
static class Simpson {
int id;
String name;
public Simpson(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Simpson simpson = (Simpson) o;
return id == simpson.id &&
name.equals(simpson.name);
}
@Override
public int hashCode() {
return id;
}
}
}
hashcode()
总是返回相同值是有效的,但不是那么高效。在这个案例中,这段代码将返回true
,所以equals()
方法总是会被执行。在这种情况下,没有性能上的改进。
网友评论