当前位置: 首页 > 后端技术 > Java

内存泄漏防雷!你真的了解重写equals()和hashcode()方法的原因吗?

时间:2023-04-01 21:34:15 Java

基本概念比较两个对象是否相等,需要调用对象的equals()方法:判断对象引用指向的对象地址是否相等。当对象地址相等时,则与该对象相关的数据也相等,包括:对象句柄对象头对象实例数据对象类型数据可以通过比较地址来判断对象是否相等。Object源对象使用Object中的equals()方法和hashCode()方法,无需重写。引用是否指向同一个对象hashCode():根据对象地址生成一个整数值Object的hashCode()方法修饰符为native:表示该方法由操作系统实现。Java调用操作系统底层代码获取Hash值publicnativeinthashCode();重写equals重写equals()方法的场景:假设有很多学生对象。默认情况下,判断多个学生对象是否相等,需要根据地址进行判断:如果对象地址相等,则数据必须相同判断是否相等的要求:当学生的姓名、年龄、性别为equal,对象被认为是相等的,对象的地址不一定需要完全一样。根据要求重写equals()方法:publicclassStudent{/**Name*/privateStringname;/**性别*/privateStringsex;/**年龄*/privateStringage;/**权重*/私有浮点权重;/**地址*/privateStringaddr;/**覆盖equals()方法*/@Overridepublicbooleanequals(Objectobj){//instanceof已经处理了obj==null的情况if(!(ObjectinstanceofStudent)){returnfalse;}学生stuObj=(Student)obj;//地址相等if(this==stuObj){r变真;}//如果对象的名字,年龄,性别等。那么两个对象等if(stuObj.name.equals(this.name)&&stuObj.sex.equals(this.sex)&&stuObj.age.equals(this.年龄)){返回真;}else{返回错误;}}publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}publicStringgetSex(){返回性别;}publicvoidsetSex(Stringsex){this.sex=sex;}publicStringgetAge(){返回年龄;}publicvoidsetAge(Stringage){this.age=age;}publicStringgetWeight(){返回重量;}publicvoidsetName(Stringweight){this.weight=weight;}publicStringgetAddr(){返回地址;}publicvoidsetAddr(Stringaddr){this.addr=addr;}}示例:publicstaticvoidmain(String[]args){Students1=newStudent();s1.setAddr("地球");s1.setAge("20");s1.setName("汤姆");s1.setSex("男");s1.setWeight(60f);学生s2=新学生();s2.setAddr("火星");s2.setAge("20");s2.setName("汤姆");s2.setSex("男");s2.setWeight(70f);如果(s1.equals(s2)){System.out.println("s1==s2");}else{System.out.println("s1!=s2");}}重写equals()方法后,会输出[s1==s2]如果不重写equals()方法,肯定会输出[s1!=s2]重写hashCode按照重写equals的方法,上面的s1和s2被认为等于Object中的hashCode()方法:在没有修改equals()方法的前提下,多次调用同一个对象,hashCode()方法返回的值必须是同一个正数。如果两个对象equals()彼此,那么这两个对象的hashcode值一定是相等的。为不同的对象生成不同的哈希码可以提高哈希表的性能。重写hashCode()方法:publicclassStudent{/*name/privateStringname;/*性别/私有字符串性别;/*年龄/私人字符串年龄;/*weight/私有浮动权重;/*address/privateStringaddr;/*weight写hashCode()方法*/@OverridepublicinthashCode(){intresult=name.hashCode();结果=17*结果+sex.hashCode();结果=17*结果+age.hashCode();returnresult;}/**覆盖equals()方法*/@Overridepublicbooleanequals(Objectobj){//instanceof已经处理了obj==null的情况if(!(ObjectinstanceofStudent)){returnfalse;}学生stuObj=(Student)obj;//地址相等if(this==stuObj){returntrue;}//如果对象的名字、年龄和性别相等。那么这两个对象是相等的}else{返回错误;}}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicStringgetSex(){returnsex;}publicvoidsetSex(Stringsex){this.sex=sex;}publicStringgetAge(){returnage;}publicvoidsetAge(Stringage){this.age=age;}publicStringgetWeight(){returnweight;}publicvoidsetName(Stringweight){this.weight=weight;}publicStringgetAddr(){returnaddr;}publicvoidsetAddr(Stringaddr){this.addr=addr;}}在两个对象中如果相等,分别放入Map和Set中:publicstaticvoidmain(String[]args){Students1=newStudent();s1.setAddr("地球");s1.setAge("20");s1.setName("汤姆");s1.setSex("男");s1.setWeight(60f);学生s2=新学生();s2.setAddr("火星");s2.setAge("20");s2.setName("汤姆");s2.setSex("男");s2.setWeight(70f);如果(s1.equals(s2)){System.out.println("s1==s2");}else{System.out.println("s1!=s2");}设置set=newHashSet();设置.添加(s1);设置.添加(s2);System.out.println(Set);}如果不重写Object的hashCode()方法,会出现:[com.oxford.Student@7852e922,com.oxford.Student@4e25154f]这不是预期的,因为Set容器具有去重功能。相等的元素不会重复显示。这就涉及到Set底层的实现。HashSet底层实现:HashSet底层是通过HashMap实现的。比较Set容器中的元素是否相等,就是通过比较对象的hashcode来判断是否相等。hashCode()的写法:先把判断对象相等的属性整理出来,然后取一个尽可能小的正整数,防止最后的结果超出int的整数范围,然后计算[正整数*hashCode属性的+另一个属性的hashCode]重复步骤/**覆盖hashCode()方法*/@OverridepublicinthashCode(){intresult=name.hashCode();结果=17*结果+sex.hashCode();结果=17*结果+age.hashCode();返回结果;#原理分析——因为没有重写父类的**Object**的**hashCode()**方法,所以**hashCode()**方法会根据生成response的**hashcode**两个对象的地址-由于两个对象是实体类创建的不同实例,所以地址肯定不同,所以**hashcode**值也不同-**Set是区分对象的唯一标准:**-两个对象的**hashcode**值是否相同-然后判断两个对象是否**相等**-**Map区分对象不是唯一标准:**-先获取保存数组的下标根据**Key**值的**hashcode**分布-然后根据**eaquals**区分是否是唯一值#HashMap###HashMap组成结构-**HashMap:**由**数组**和**链表**组成###HashMap的存储-**HashMap的存储:**-一个对象存储在**HashMap**中的位置是确定的通过**key**的**hashcode**值-**HashMap查找key:**-在查找**key**时,hashMap**会首先根据**key**的值**hashcode**通过取余算法定位到数组的位置——然后根据**key**的**equals**方法匹配相同的**key**值得到对应的对象——**存储规则:**-取**Key**的**hashcode**和**HashMap**的容量进行**求余**运算得到数组中存放**Key**的下标-**HashMaplookupkey:**-获取**key**在数组中的位置-匹配得到对应的**key**值对象-然后根据**key.equals()**得到key对应的数据对象-**HashMap中的hashCode:**-如果没有**hashcode**,说明**HashMap**在存储时没有规律可循