java重写hashcode_正确重写hashCode的办法

17cef9244bdb4ce0988a7dd0215b0577.png

——————————————————————————————————————————

正确重写hashCode的办法

[1]. hashCode重写成相同的值的缺点

将所有对象的hashCode都返回一样的值是不科学的。比如a1和a3这两个根本不同的对象,就没有必要去比较equals,增加无谓的计算量。所以应该对象本身的内容 (属性)来重写hashCode。

一旦两个对象内部不一样,就直接判定出hashCode不一样,不用再调用equals进行比较。

[2]. 正确书写hashCode的办法:

【原则】按照equals( )中比较两个对象是否一致的条件用到的属性来重写hashCode()。

{1}. 常用的办法就是利用涉及到的的属性进行线性组合。

{2}.线性组合过程中涉及到的组合系数自定义即可。

注意,拼接之后的数值不能超过整形的表达范围。

{3}.公式:属性1的int形式+ C1*属性2的int形式+  C2*属性3的int形式+ …

【技巧】当属性是引用类型的时候,如果已经重写过hashCode(),那么这个引用属性的int形式就是直接调用属性已有的hashCode值。

最典型的就是这个属性是字符串类型的,String类型已经重写了hashCode()方法,所以直接拿来使用即可。

——————————————————————————————————————————

(1). 主要代码

class Person{

private String name;

private int age;

public static void sop(Object o){

System.out.println(o);

}

public Person(String name, int age){

this.name =name;

this.age =age;

}

public void setName(String name){

this.name =name;

}

public String getName(){

return this.name;

}

public void setAge(int age){

this.age =age;

}

public int getAge(){

return this.age;

}

public String toString(){

return this.name+"::"+this.age;

}

//equals已经重写

public boolean equals(Object obj){

if(!(obj instanceof Person)){

return false;

}

Person p =(Person)obj;

//用来查看equals方法是否被调用

sop(this.name +".......equals......."+ p.name);

//认为名字相同并且年龄一样大的两个对象是一个

return this.name.equals(p.name) && this.age == p.age;

}

}

(2). 将hashCode()重写成相同的值-----解决HashSet中重复添加

[1]. 问题:内容相同但是地址不同的自定义对象如何避免重复的内容添加到HashSet中?

【解决办法】必须重写hashCode和equals这两个方法

{1}. 此时根据底层哈希表的存储方式:哈希表会将具有相同哈希值的元素依次顺延。

{2}. hashCode值相同,HashSet在存储对象的时候,equals方法就会起作用

{3}. 示例代码:为Person类重写如下的hashCode代码

public int hashCode(){

System.out.println(this.name +"...hashCode");

return 60;

}

这样,每一个Person对象都具有相同的哈希值。

打印结果:

f54cd6aa22c6ed72210aab648505fd38.png

【HashSet添加过程分析】

【1】a1率先存入HashSet中

添加的时候,调用一次a1的hashCode方法,打印一次a1...hashCode。由于开始HashSet中没有内容,所以没有调用a1的equals方法。

内存图如下:

cfef0935fb64b29be76e585976610420.png

【2】当a2要存入HashSet的时候,HashSet首先调用a2的hashCode方法,此时打印出a2...hashCode。发现a2的hashCode也是0x3c和a1的地址值都是一样的,此时要和a1进行内容比较,打印出a2.......equals.......a1。但是发现name和age都不一样,所以equals返回false。此时HashSet就将这个a2存到集合中来。

内存图如下:

5e25f960f5e81e25e7cb3c8949100fd1.png

【3】当a3要存入HashSet的时候,HashSet首先调用a3的hashCode方法,查看有没有地址相同的元素,此时打印出a3...hashCode。此时集合中已经存在两个元素a1和a2,发现a3的hashCode也是0x3c和a1、a2的地址值都是一样的,此时要一一和这些对象的内容进行比较。

当a3和a2的进行比较时,a3的equals方法被调用,打印出a3.......equals.......a2。 比较发现a3和a2是地址相同但是内容不同的元素。

a3再和a1进行比较,a3的equals方法再次被调用,打印出a3.......equals.......a1。

比较发现a3和a1仍然是地址相同但是内容不同的元素。

a3就被认为是集合中以前并不存在的元素,所以仍然被添加进来。

内存图如下:

960be554ddac98f5dcbf8a04e1a44bd9.png

【4】当运行到第二个a2要添加进来的时候,先调用hashCode,所以马上打印a2...hashCode。

但是发现,和a2 hashCode相同的元素有a1、a2和a3。这个a2要和集合中的a1、a2和a3都做内容上是否相同的比较。

a2先比较集合中的a3,调用a2的equals方法,打印出a2.......equals.......a3。

位置相同,但是内容不同。

a2再比较集合中的a2,调用a2的equals方法,打印出a2.......equals.......a2。

但是发现两者内容、地址均相同,是重复的元素,不能加到集合中来,所以没有必要再把这个a2和集合中的a1进行比较。所以没有打印a2.......equals.......a1

3245a2772fc472fda0326f68ae36cb2b.png

(3). 正确重写hashCode的办法

[1]. hashCode重写成相同的值的缺点

将所有对象的hashCode都返回一样的值是不科学的。比如a1和a3这两个根本不同的对象,就没有必要去比较equals,增加无谓的计算量。所以应该对象本身的内容 (属性)来重写hashCode。

一旦两个对象内部不一样,就直接判定出hashCode不一样,不用再调用equals进行比较。

[2]. 正确书写hashCode的办法:

【原则】按照equals( )中比较两个对象是否一致的条件用到的属性来重写hashCode()。

{1}. 常用的办法就是利用涉及到的的属性进行线性组合。

{2}.线性组合过程中涉及到的组合系数自定义即可。

注意,拼接之后的数值不能超过整形的表达范围。

{3}.公式:属性1的int形式+ C1*属性2的int形式+  C2*属性3的int形式+ …

【技巧】当属性是引用类型的时候,如果已经重写过hashCode(),那么这个引用属性的int形式就是直接调用属性已有的hashCode值。

最典型的就是这个属性是字符串类型的,String类型已经重写了hashCode()方法,所以直接拿来使用即可。

e.g. 分析案例

这个例子中,重写的equals方法中是通过name和age来判定两个对象是否一致的。所以,就通过Person的这两个属性name和age的线性组合来获取这个Person的hashCode值。注意到name是String类型的,所以,可以调用name的hashCode()来直接获取name对应的int值。

这里重写的hashCode方法是:

public inthashCode(){

sop(this.name +"......hashCode");

return this.name.hashCode() + 29*age;

}

打印结果:

0bbd31fc8145e3bde4e10971f99e8f28.png

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值