equals()
equals() 的作用是 用来判断两个对象是否相等。
Object.java中的equals()方法
public boolean equals(Object var1) {
return this == var1;
}
通过判断两个对象的地址是否相等(即两个引用是否指向同一个对象),来判断两个对象是否相等。
既然Object.java中定义了equals()方法,这就意味着所有的Java类都实现了equals()方法,所有的类都可以通过equals()去比较两个对象是否相等。 使用默认的“equals()”方法,等价于“==”方法。
通过继承类“是否覆盖了equals()方法”,可将equals()的使用分为两类。
1)某个类没有覆盖equals()方法,实际上比较两个对象是不是同一个对象,等价于使用“==”方法去比较。
2)可以覆盖equals()方法,通过其他的方式去比较两个对象是否相等。通常的方法是比较两个对象的值(内容)是否相等。
String.java中的equals()方法
public boolean equals(Object var1) {
if (this == var1) {
return true;
} else {
if (var1 instanceof String) {
String var2 = (String)var1;
int var3 = this.value.length;
if (var3 == var2.value.length) {
char[] var4 = this.value;
char[] var5 = var2.value;
for(int var6 = 0; var3-- != 0; ++var6) {
if (var4[var6] != var5[var6]) {
return false;
}
}
return true;
}
}
return false;
}
}
java对equals()重写的要求
1)对称性,a.equals(b)与b.equals(a)的返回结果一致
2)反射性,a.equals(a)一定是返回true
3)类推性,a.equals(b),b.equals(c) 则有 a.equals(c)
4)一致性,只要a与b的内容不发生变化,则a.equals(b)的对比结果不会发生变化
5)a.equals(null)一定返回false,a.equals(其他类型对象)一定返回false,例如通常使用如下语句判断对象类型:
(var1 instanceof String)
hashCode()
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
Object.java中的hashCode()方法
public native int hashCode();
是一个本地方法,java类中不提供实现体,无final关键字修饰,可以由继承类重写。
延伸:
当一个类第一次被使用到时,这个类的字节码会被加载到内存,并且只会加载一次。在这个被加载的字节码的入口维持着一个该类所有方法描述符的list,这些方法描述符包含这样一些信息:方法代码存于何处,它有哪些参数,方法的描述符(public之类)等。
如果一个方法描述符内有native,这个描述符块将有一个指向该方法的实现的指针。这些实现在一些dll文件内,但是它们会被操作系统加载到java程序的地址空间。当一个带有本地方法的类被加载时,其相关的dll并未被加载,因此指向方法实现的指针并不会被设置。当本地方法被调用之前,这些dll才会被加载,这是通过调用java.system.loadLibrary()实现的。
既然Object.java中定义了hashCode()方法,这就意味着所有的Java类都实现了hashCode()方法。虽然,每个Java类都包含hashCode() 函数,但是只有在创建某个类的散列表时,hashCode()才有用,其作用是:确定该类的每一个对象在散列表中的位置。创建类的对象,对象数组时hashCode()方法无用。
散列表指的是Java集合中本质是散列表的类,例如:HashMap,Hashtable,HashSet。
equals()与 hashCode()
要理清楚equals()与hashCode()的联系,需要将类的集合区分为散列表集合和非散列表集合来梳理。
1)如果一个类,不需要存储在散列表集合中,这种情况下直接使用equals()来判断类是否相等,hashCode()无任何作用;
2)如果一个类,需要存储在散列表集合中(例如:HashSet,HashTable,HashMap),则需要区别equals()和hashCode()的使用。
先来看情况一:不创建类的散列表集合
public class differHashCodeAndEqual1 {
private static class Person
{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
{
return false;
}
if(obj instanceof Person)
{
if(this == obj){
return true;
}
else
{
return (this.name==((Person) obj).name && this.age ==((Person) obj).age);
}
}
return false;
}
}
public static void main(String[] args) {
Person p1 = new Person("sandy",19);
Person p2 = new Person("sandy",19);
Person p3 = new Person("Monica",21);
System.out.println("p1.equals(p2): "+p1.equals(p2)+" p1(hashCode()): "+p1.hashCode()+" p2(hashCode()): "+p2.hashCode());
System.out.println("p1.equals(p3): "+p1.equals(p3)+" p1(hashCode()): "+p1.hashCode()+" p3(hashCode()): "+p3.hashCode());
}
}
输出:
p1.equals(p2): true p1(hashCode()): 1163157884 p2(hashCode()): 1956725890
p1.equals(p3): false p1(hashCode()): 1163157884 p3(hashCode()): 356573597
学习情况二:创建类的散列表集合,但是没有重写hashCode()方法
public class differHashCodeAndEqual1 {
private static class Person
{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
{
return false;
}
if(obj instanceof Person)
{
if(this == obj){
return true;
}
else
{
return (this.name==((Person) obj).name && this.age ==((Person) obj).age);
}
}
return false;
}
@Override
public String toString() {
return "name: " + name + " age: "+ age ;
}
}
public static void main(String[] args) {
Person p1 = new Person("sandy",19);
Person p2 = new Person("sandy",19);
Person p3 = new Person("Monica",21);
HashSet hashSet = new HashSet();
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
System.out.println("p1.equals(p2): "+p1.equals(p2)+" p1(hashCode()): "+p1.hashCode()+" p2(hashCode()): "+p2.hashCode());
System.out.println("p1.equals(p3): "+p1.equals(p3)+" p1(hashCode()): "+p1.hashCode()+" p3(hashCode()): "+p3.hashCode());
System.out.println("hashSet:" + hashSet);
}
}
输出:
p1.equals(p2): true p1(hashCode()): 1163157884 p2(hashCode()): 1956725890
p1.equals(p3): false p1(hashCode()): 1163157884 p3(hashCode()): 356573597
hashSet:[name: sandy age: 19, name: sandy age: 19, name: Monica age: 21]
这时可以看到,p1,p2的equals()结果返回为true,但是hashCode()结果为不同,HashSet的add方法向hashSet中添加了[重复的]元素。
正确的情况三:创建类的散了表集合,重写equals()方法和hashCode()方法,使得HashSet集合中无重复添加的元素。
public class differHashCodeAndEqual1 {
private static class Person
{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
{
return false;
}
if(obj instanceof Person)
{
if(this == obj){
return true;
}
else
{
return (this.name==((Person) obj).name && this.age ==((Person) obj).age);
}
}
return false;
}
@Override
public int hashCode() {
int nameHash = name.toUpperCase().hashCode();
return nameHash ^ age;
}
@Override
public String toString() {
return "name: " + name + " age: "+ age ;
}
}
public static void main(String[] args) {
Person p1 = new Person("sandy",19);
Person p2 = new Person("sandy",19);
Person p3 = new Person("Monica",21);
HashSet hashSet = new HashSet();
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
System.out.println("p1.equals(p2): "+p1.equals(p2)+" p1(hashCode()): "+p1.hashCode()+" p2(hashCode()): "+p2.hashCode());
System.out.println("p1.equals(p3): "+p1.equals(p3)+" p1(hashCode()): "+p1.hashCode()+" p3(hashCode()): "+p3.hashCode());
System.out.println("hashSet:" + hashSet);
}
}
输出:
p1.equals(p2): true p1(hashCode()): 78665798 p2(hashCode()): 78665798
p1.equals(p3): false p1(hashCode()): 78665798 p3(hashCode()): -2015168530
hashSet:[name: sandy age: 19, name: Monica age: 21]
结论:
1)、如果两个对象equals()结果相等,那么它们的hashCode()值一定相同。
2)、如果两个对象hashCode()相等,它们并不一定equals()相等。
网友评论