有免费的网址吗,网站优化做网站优化,做冷库的网站,上海网站建设seo1888Java hashCode() 和 equals()的若干问题解答
本章的内容主要解决下面几个问题#xff1a;
1 equals() 的作用是什么#xff1f;
2 equals() 与 的区别是什么#xff1f;
3 hashCode() 的作用是什么#xff1f;
4 hashCode() 和 equals() 之间有什么联系#xff1f; …Java hashCode() 和 equals()的若干问题解答
本章的内容主要解决下面几个问题
1 equals() 的作用是什么
2 equals() 与 的区别是什么
3 hashCode() 的作用是什么
4 hashCode() 和 equals() 之间有什么联系
第1部分 equals() 的作用
equals() 的作用是 用来判断两个对象是否相等。
equals() 定义在JDK的Object.java中。通过判断两个对象的地址是否相等(即是否是同一个对象)来区分它们是否相等。源码如下
public boolean equals(Object obj) { return (this obj); } 既然Object.java中定义了equals()方法这就意味着所有的Java类都实现了equals()方法所有的类都可以通过equals()去比较两个对象是否相等。 但是我们已经说过使用默认的“equals()”方法等价于“”方法。因此我们通常会重写equals()方法若两个对象的内容相等则equals()方法返回true否则返回fasle。
下面根据“类是否覆盖equals()方法”将它分为2类。 (01) 若某个类没有覆盖equals()方法当它的通过equals()比较两个对象时实际上是比较两个对象是不是同一个对象。这时等价于通过“”去比较这两个对象。 (02) 我们可以覆盖类的equals()方法来让equals()通过其它方式比较两个对象是否相等。通常的做法是若两个对象的内容相等则equals()方法返回true否则返回fasle。
下面举例对上面的2种情况进行说明。
“没有覆盖equals()方法”的情况
代码如下 (EqualsTest1.java)
import java.util.*;
import java.lang.Comparable;/*** desc equals()的测试程序。** author skywang* emai kuiwu-wang163.com*/
public class EqualsTest1{public static void main(String[] args) {// 新建2个相同内容的Person对象// 再用equals比较它们是否相等Person p1 new Person(eee, 100);Person p2 new Person(eee, 100);System.out.printf(%s\n, p1.equals(p2));}/*** desc Person类。*/private static class Person {int age;String name;public Person(String name, int age) {this.name name;this.age age;}public String toString() {return name - age;}}
}View Code 运行结果
false 结果分析 我们通过 p1.equals(p2) 来“比较p1和p2是否相等时”。实际上调用的Object.java的equals()方法即调用的 (p1p2) 。它是比较“p1和p2是否是同一个对象”。而由 p1 和 p2 的定义可知它们虽然内容相同但它们是两个不同的对象因此返回结果是false。覆盖equals()方法的情况
我们修改上面的EqualsTest1.java覆盖equals()方法。
代码如下 (EqualsTest2.java)
import java.util.*;
import java.lang.Comparable;/*** desc equals()的测试程序。** author skywang* emai kuiwu-wang163.com*/
public class EqualsTest2{public static void main(String[] args) {// 新建2个相同内容的Person对象// 再用equals比较它们是否相等Person p1 new Person(eee, 100);Person p2 new Person(eee, 100);System.out.printf(%s\n, p1.equals(p2));}/*** desc Person类。*/private static class Person {int age;String name;public Person(String name, int age) {this.name name;this.age age;}public String toString() {return name - age;}/*** desc 覆盖equals方法*/Overridepublic boolean equals(Object obj){if(obj null){return false;}//如果是同一个对象返回true反之返回falseif(this obj){return true;}//判断是否类型相同if(this.getClass() ! obj.getClass()){return false;}Person person (Person)obj;return name.equals(person.name) ageperson.age;}}
}View Code 运行结果
true 结果分析
我们在EqualsTest2.java 中重写了Person的equals()函数当两个Person对象的 name 和 age 都相等则返回true。 因此运行结果返回true。
讲到这里顺便说一下java对equals()的要求。有以下几点
对称性如果x.equals(y)返回是true那么y.equals(x)也应该返回是true。反射性x.equals(x)必须返回是true。类推性如果x.equals(y)返回是true而且y.equals(z)返回是true那么z.equals(x)也应该返回是true。一致性如果x.equals(y)返回是true只要x和y内容一直不变不管你重复x.equals(y)多少次返回都是true。非空性x.equals(null)永远返回是falsex.equals(和x不同类型的对象)永远返回是false。
现在再回顾一下equals()的作用判断两个对象是否相等。当我们重写equals()的时候可千万不好将它的作用给改变了
第2部分 equals() 与 的区别是什么 : 它的作用是判断两个对象的地址是不是相等。即判断两个对象是不试同一个对象。
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况(前面第1部分已详细介绍过) 情况1类没有覆盖equals()方法。则通过equals()比较该类的两个对象时等价于通过“”比较这两个对象。 情况2类覆盖了equals()方法。一般我们都覆盖equals()方法来两个对象的内容相等若它们的内容相等则返回true(即认为这两个对象相等)。
第3部分 hashCode() 的作用
hashCode() 的作用是获取哈希码也称为散列码它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashCode() 定义在JDK的Object.java中这就意味着Java中的任何类都包含有hashCode() 函数。 虽然每个Java类都包含hashCode() 函数。但是仅仅当创建并某个“类的散列表”(关于“散列表”见下面说明)时该类的hashCode() 才有用(作用是确定该类的每一个对象在散列表中的位置其它情况下(例如创建类的单个对象或者创建类的对象数组等等)类的hashCode() 没有作用。 上面的散列表指的是Java集合中本质是散列表的类如HashMapHashtableHashSet。 也就是说hashCode() 在散列表中才有用在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码进而确定该对象在散列表中的位置。OK至此我们搞清楚了hashCode()的作用是获取散列码。但是散列码是用来干什么的呢为什么散列表需要散列码呢要解决这些问题就需要理解散列表
为了能理解后面的内容这里简单的介绍一下散列码的作用。
我们都知道散列表存储的是键值对(key-value)它的特点是能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码 散列表的本质是通过数组实现的。当我们要获取散列表中的某个“值”时实际上是要获取数组中的某个位置的元素。而数组的位置就是通过“键”来获取的更进一步说数组的位置是通过“键”对应的散列码计算得到的。 下面我们以HashSet为例来深入说明hashCode()的作用。 假设HashSet中已经有1000个元素。当插入第1001个元素时需要怎么处理因为HashSet是Set集合它允许有重复元素。“将第1001个元素逐个的和前面1000个元素进行比较”显然这个效率是相等低下的。散列表很好的解决了这个问题它根据元素的散列码计算出元素在散列表中的位置然后将元素插入该位置即可。对于相同的元素自然是只保存了一个。由此可知若两个元素相等它们的散列码一定相等但反过来确不一定。在散列表中1、如果两个对象相等那么它们的hashCode()值一定要相同2、如果两个对象hashCode()相等它们并不一定相等。注意这是在散列表中的情况。在非散列表中一定如此对“hashCode()的作用”就谈这么多。
第4部分 hashCode() 和 equals() 的关系
接下面我们讨论另外一个话题。网上很多文章将 hashCode() 和 equals 关联起来有的讲的不透彻有误导读者的嫌疑。在这里我自己梳理了一下 “hashCode() 和 equals()的关系”。
我们以“类的用途”来将“hashCode() 和 equals()的关系”分2种情况来说明。 第一种 不会创建“类对应的散列表” 这里所说的“不会创建类对应的散列表”是说我们不会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中用到该类。例如不会创建该类的HashSet集合。在这种情况下该类的“hashCode() 和 equals() ”没有半毛钱关系的这种情况下equals() 用来比较该类的两个对象是否相等。而hashCode() 则根本没有任何作用所以不用理会hashCode()。下面我们通过示例查看类的两个对象相等 以及 不等时hashCode()的取值。
源码如下 (NormalHashCodeTest.java)
import java.util.*;
import java.lang.Comparable;/*** desc equals()的测试程序。** author skywang* emai kuiwu-wang163.com*/
public class EqualsTest3{public static void main(String[] args) {// 新建2个相同内容的Person对象// 再用equals比较它们是否相等Person p1 new Person(eee, 100);Person p2 new Person(eee, 100);System.out.printf(p1.equals(p2) : %s\n, p1.equals(p2));System.out.printf(p1p2 : %s\n, p1p2);}/*** desc Person类。*/private static class Person {int age;String name;public Person(String name, int age) {this.name name;this.age age;}public String toString() {return name - age;}/*** desc 覆盖equals方法*/Overridepublic boolean equals(Object obj){if(obj null){return false;}//如果是同一个对象返回true反之返回falseif(this obj){return true;}//判断是否类型相同if(this.getClass() ! obj.getClass()){return false;}Person person (Person)obj;return name.equals(person.name) ageperson.age;}}
}View Code 运行结果
p1.equals(p2) : true; p1(1169863946) p2(1901116749) p1.equals(p3) : false; p1(1169863946) p3(2131949076) 从结果也可以看出p1和p2相等的情况下hashCode()也不一定相等。 第二种 会创建“类对应的散列表” 这里所说的“会创建类对应的散列表”是说我们会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中用到该类。例如会创建该类的HashSet集合。在这种情况下该类的“hashCode() 和 equals() ”是有关系的1)、如果两个对象相等那么它们的hashCode()值一定相同。这里的相等是指通过equals()比较两个对象时返回true。2)、如果两个对象hashCode()相等它们并不一定相等。因为在散列表中hashCode()相等即两个键值对的哈希值相等。然而哈希值相等并不一定能得出键值对相等。补充说一句“两个不同的键值对哈希值相等”这就是哈希冲突。此外在这种情况下。若要判断两个对象是否相等除了要覆盖equals()之外也要覆盖hashCode()函数。否则equals()无效。例如创建Person类的HashSet集合必须同时覆盖Person类的equals() 和 hashCode()方法。 如果单单只是覆盖equals()方法。我们会发现equals()方法没有达到我们想要的效果。
参考代码 (ConflictHashCodeTest1.java)
import java.util.*;
import java.lang.Comparable;/*** desc 比较equals() 返回true 以及 返回false时 hashCode()的值。** author skywang* emai kuiwu-wang163.com*/
public class NormalHashCodeTest{public static void main(String[] args) {// 新建2个相同内容的Person对象// 再用equals比较它们是否相等Person p1 new Person(eee, 100);Person p2 new Person(eee, 100);Person p3 new Person(aaa, 200);System.out.printf(p1.equals(p2) : %s; p1(%d) p2(%d)\n, p1.equals(p2), p1.hashCode(), p2.hashCode());System.out.printf(p1.equals(p3) : %s; p1(%d) p3(%d)\n, p1.equals(p3), p1.hashCode(), p3.hashCode());}/*** desc Person类。*/private static class Person {int age;String name;public Person(String name, int age) {this.name name;this.age age;}public String toString() {return name - age;}/*** desc 覆盖equals方法*/public boolean equals(Object obj){if(obj null){return false;}//如果是同一个对象返回true反之返回falseif(this obj){return true;}//判断是否类型相同if(this.getClass() ! obj.getClass()){return false;}Person person (Person)obj;return name.equals(person.name) ageperson.age;}}
}View Code 运行结果
p1.equals(p2) : true; p1(1169863946) p2(1690552137) set:[(eee, 100), (eee, 100), (aaa, 200)] 结果分析 我们重写了Person的equals()。但是很奇怪的发现HashSet中仍然有重复元素p1 和 p2。为什么会出现这种情况呢这是因为虽然p1 和 p2的内容相等但是它们的hashCode()不等所以HashSet在添加p1和p2的时候认为它们不相等。参考代码 (ConflictHashCodeTest1.java)
import java.util.*;
import java.lang.Comparable;/*** desc 比较equals() 返回true 以及 返回false时 hashCode()的值。** author skywang* emai kuiwu-wang163.com*/
public class ConflictHashCodeTest1{public static void main(String[] args) {// 新建Person对象Person p1 new Person(eee, 100);Person p2 new Person(eee, 100);Person p3 new Person(aaa, 200);// 新建HashSet对象HashSet set new HashSet();set.add(p1);set.add(p2);set.add(p3);// 比较p1 和 p2 并打印它们的hashCode()System.out.printf(p1.equals(p2) : %s; p1(%d) p2(%d)\n, p1.equals(p2), p1.hashCode(), p2.hashCode());// 打印setSystem.out.printf(set:%s\n, set);}/*** desc Person类。*/private static class Person {int age;String name;public Person(String name, int age) {this.name name;this.age age;}public String toString() {return (name , age);}/*** desc 覆盖equals方法*/Overridepublic boolean equals(Object obj){if(obj null){return false;}//如果是同一个对象返回true反之返回falseif(this obj){return true;}//判断是否类型相同if(this.getClass() ! obj.getClass()){return false;}Person person (Person)obj;return name.equals(person.name) ageperson.age;}}
}View Code 运行结果
p1.equals(p2) : true; p1(1169863946) p2(1690552137) set:[(eee, 100), (eee, 100), (aaa, 200)] 结果分析 我们重写了Person的equals()。但是很奇怪的发现HashSet中仍然有重复元素p1 和 p2。为什么会出现这种情况呢这是因为虽然p1 和 p2的内容相等但是它们的hashCode()不等所以HashSet在添加p1和p2的时候认为它们不相等。下面我们同时覆盖equals() 和 hashCode()方法。
参考代码 (ConflictHashCodeTest2.java)
import java.util.*;
import java.lang.Comparable;/*** desc 比较equals() 返回true 以及 返回false时 hashCode()的值。** author skywang* emai kuiwu-wang163.com*/
public class ConflictHashCodeTest2{public static void main(String[] args) {// 新建Person对象Person p1 new Person(eee, 100);Person p2 new Person(eee, 100);Person p3 new Person(aaa, 200);Person p4 new Person(EEE, 100);// 新建HashSet对象HashSet set new HashSet();set.add(p1);set.add(p2);set.add(p3);// 比较p1 和 p2 并打印它们的hashCode()System.out.printf(p1.equals(p2) : %s; p1(%d) p2(%d)\n, p1.equals(p2), p1.hashCode(), p2.hashCode());// 比较p1 和 p4 并打印它们的hashCode()System.out.printf(p1.equals(p4) : %s; p1(%d) p4(%d)\n, p1.equals(p4), p1.hashCode(), p4.hashCode());// 打印setSystem.out.printf(set:%s\n, set);}/*** desc Person类。*/private static class Person {int age;String name;public Person(String name, int age) {this.name name;this.age age;}public String toString() {return name - age;}/*** desc重写hashCode*/Overridepublic int hashCode(){int nameHash name.toUpperCase().hashCode();return nameHash ^ age;}/*** desc 覆盖equals方法*/Overridepublic boolean equals(Object obj){if(obj null){return false;}//如果是同一个对象返回true反之返回falseif(this obj){return true;}//判断是否类型相同if(this.getClass() ! obj.getClass()){return false;}Person person (Person)obj;return name.equals(person.name) ageperson.age;}}
}View Code 运行结果
p1.equals(p2) : true; p1(68545) p2(68545) p1.equals(p4) : false; p1(68545) p4(68545) set:[aaa - 200, eee - 100] 结果分析 这下equals()生效了HashSet中没有重复元素。比较p1和p2我们发现它们的hashCode()相等通过equals()比较它们也返回true。所以p1和p2被视为相等。比较p1和p4我们发现虽然它们的hashCode()相等但是通过equals()比较它们返回false。所以p1和p4被视为不相等。by https://www.cnblogs.com/skywang12345/p/3324958.html