做网站需要哪些准备,易居房产cms,网站编程员工资,wordpress可爱主题下载每天一道面试题#xff0c;陪你突击金九银十#xff01; 上一篇关于介绍Object类下的几种方法时面试题时#xff0c;提到equals()和hashCode()方法可能引出关于“hashCode() 和 equals() 之间的关系#xff1f;”的面试题#xff0c;本篇来解析一下这道基础面试题。 先祭一… 每天一道面试题陪你突击金九银十 上一篇关于介绍Object类下的几种方法时面试题时提到equals()和hashCode()方法可能引出关于“hashCode() 和 equals() 之间的关系”的面试题本篇来解析一下这道基础面试题。 先祭一张图可以思考一下为什么 介绍 equals() 的作用是用来判断两个对象是否相等。 hashCode() 的作用是获取哈希码也称为散列码它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。 关系 我们以“类的用途”来将“hashCode() 和 equals()的关系”分2种情况来说明。 1、不会创建“类对应的散列表” 这里所说的“不会创建类对应的散列表”是说我们不会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中用到该类。例如不会创建该类的HashSet集合。 在这种情况下该类的“hashCode() 和 equals() ”没有半毛钱关系的equals() 用来比较该类的两个对象是否相等。而hashCode() 则根本没有任何作用。 下面我们通过示例查看类的两个对象相等 以及 不等时hashCode()的取值。 import java.util.*;import java.lang.Comparable;/** * desc 比较equals() 返回true 以及 返回false时 hashCode()的值。 * */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反之返回false if(this obj){ return true; } //判断是否类型相同 if(this.getClass() ! obj.getClass()){ return false; } Person person (Person)obj; return name.equals(person.name) ageperson.age; } }} 运行结果 p1.equals(p2) : true; p1(1169863946) p2(1901116749)p1.equals(p3) : false; p1(1169863946) p3(2131949076) 从结果也可以看出p1和p2相等的情况下hashCode()也不一定相等。 2、会创建“类对应的散列表” 这里所说的“会创建类对应的散列表”是说我们会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中用到该类。例如会创建该类的HashSet集合。 在这种情况下该类的“hashCode() 和 equals() ”是有关系的 如果两个对象相等那么它们的hashCode()值一定相同。这里的相等是指通过equals()比较两个对象时返回true。 如果两个对象hashCode()相等它们并不一定相等。因为在散列表中hashCode()相等即两个键值对的哈希值相等。然而哈希值相等并不一定能得出键值对相等。补充说一句“两个不同的键值对哈希值相等”这就是哈希冲突。 此外在这种情况下。若要判断两个对象是否相等除了要覆盖equals()之外也要覆盖hashCode()函数。否则equals()无效。 举例创建Person类的HashSet集合必须同时覆盖Person类的equals() 和 hashCode()方法。 如果单单只是覆盖equals()方法。我们会发现equals()方法没有达到我们想要的效果。 import java.util.*;import java.lang.Comparable;/** * desc 比较equals() 返回true 以及 返回false时 hashCode()的值。 * */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()); // 打印set System.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方法 */ Override public boolean equals(Object obj){ if(obj null){ return false; } //如果是同一个对象返回true反之返回false if(this obj){ return true; } //判断是否类型相同 if(this.getClass() ! obj.getClass()){ return false; } Person person (Person)obj; return name.equals(person.name) ageperson.age; } }} 运行结果 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()方法呢 import java.util.*;import java.lang.Comparable;/** * desc 比较equals() 返回true 以及 返回false时 hashCode()的值。 * */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()); // 打印set System.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 */ Override public int hashCode(){ int nameHash name.toUpperCase().hashCode(); return nameHash ^ age; } /** * desc 覆盖equals方法 */ Override public boolean equals(Object obj){ if(obj null){ return false; } //如果是同一个对象返回true反之返回false if(this obj){ return true; } //判断是否类型相同 if(this.getClass() ! obj.getClass()){ return false; } Person person (Person)obj; return name.equals(person.name) ageperson.age; } }} 运行结果 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被视为不相等。 原则 1.同一个对象没有发生过修改无论何时调用hashCode()得到的返回值必须一样。如果一个key对象在put的时候调用hashCode()决定了存放的位置而在get的时候调用hashCode()得到了不一样的返回值这个值映射到了一个和原来不一样的地方那么肯定就找不到原来那个键值对了。 2.hashCode()的返回值相等的对象不一定相等通过hashCode()和equals()必须能唯一确定一个对象。不相等的对象的hashCode()的结果可以相等。hashCode()在注意关注碰撞问题的时候也要关注生成速度问题完美hash不现实。 3.一旦重写了equals()函数重写equals的时候还要注意要满足自反性、对称性、传递性、一致性就必须重写hashCode()函数。而且hashCode()的生成哈希值的依据应该是equals()中用来比较是否相等的字段。 如果两个由equals()规定相等的对象生成的hashCode不等对于hashMap来说他们很可能分别映射到不同位置没有调用equals()比较是否相等的机会两个实际上相等的对象可能被插入不同位置出现错误。其他一些基于哈希方法的集合类可能也会有这个问题 顶尖架构师栈 关注回复关键字 【C01】超10G后端学习面试资源 【IDEA】最新IDEA激活工具和码及教程 【JetBrains软件名】 最新软件激活工具和码及教程 工具码教程 转载于https://mp.weixin.qq.com/s/vdCW5ZwZUJ3oe9-qLVGnZw 本文由 mdnice 多平台发布