SpringBoot 重写hashCode方法和equals方法
Posted 张志翔 ̮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 重写hashCode方法和equals方法相关的知识,希望对你有一定的参考价值。
一、不重写hashCode方法和equals方法
1. Phone对象
代码如下(示例):
public class Phone
private String name;
private Integer price;
public Phone(String name, Integer price)
this.name = name;
this.price = price;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Integer getPrice()
return price;
public void setPrice(Integer price)
this.price = price;
@Override
public String toString()
return "Phone" +
"name='" + name + '\\'' +
", price=" + price +
'';
2. 将Phone 对象添加入set
代码如下(示例):
public static void main(String[] args)
HashSet hashSet = new HashSet();
hashSet.add(new Phone("华为", 6666));
hashSet.add(new Phone("小米", 1999));
hashSet.add(new Phone("华为", 6666));
Iterator iterator = hashSet.iterator();
while (iterator.hasNext())
System.out.println(iterator.next().toString());
3. 运行结果
因为没有重写hashCode方法和equals方法,导致数据重复添加
如果对象未重写 hashCode方法,则会使用父类Object的hashCode,Object的hashCode每次new一个对象就会有不同的hash值,如果不重写,即使相同的对象也能被添加。
二、重写hashCode方法和equals方法
1. Phone对象
代码如下(示例):
public class Phone
private String name;
private Integer price;
public Phone(String name, Integer price)
this.name = name;
this.price = price;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Integer getPrice()
return price;
public void setPrice(Integer price)
this.price = price;
@Override
public String toString()
return "Phone" +
"name='" + name + '\\'' +
", price=" + price +
'';
@Override
public boolean equals(Object o)
if (this == o) return true;
if (!(o instanceof Phone)) return false;
Phone phone = (Phone) o;
return getName().equals(phone.getName()) &&
getPrice().equals(phone.getPrice());
@Override
public int hashCode()
return Objects.hash(getName(), getPrice());
2. 将Phone 对象添加入set
代码如下(示例):
public static void main(String[] args)
HashSet hashSet = new HashSet();
hashSet.add(new Phone("华为", 6666));
hashSet.add(new Phone("小米", 1999));
hashSet.add(new Phone("华为", 6666));
Iterator iterator = hashSet.iterator();
while (iterator.hasNext())
System.out.println(iterator.next().toString());
3. 运行结果
重写hashCode方法和equals方法后就解决了数据重复添加的问题。
思考:
重写后如果改变了对象的属性,那么计算出的hashCode还是原来的吗?
答案在下面
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
三、对象做为可变key
1. Phone对象
代码如下(示例):
public class Phone
private String serialNumber;
private String name;
private Integer price;
public Phone(String serialNumber, String name, Integer price)
this.serialNumber = serialNumber;
this.name = name;
this.price = price;
public String getSerialNumber()
return serialNumber;
public void setSerialNumber(String serialNumber)
this.serialNumber = serialNumber;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Integer getPrice()
return price;
public void setPrice(Integer price)
this.price = price;
@Override
public String toString()
return "Phone" +
"serialNumber='" + serialNumber + '\\'' +
", name='" + name + '\\'' +
", price=" + price +
'';
@Override
public boolean equals(Object o)
if (this == o) return true;
if (!(o instanceof Phone)) return false;
Phone phone = (Phone) o;
return getSerialNumber().equals(phone.getSerialNumber()) &&
getName().equals(phone.getName()) &&
getPrice().equals(phone.getPrice());
@Override
public int hashCode()
return Objects.hash(getSerialNumber(), getName(), getPrice());
2. 将Phone 对象作为key放入map
代码如下(示例):
public static void main(String[] args)
Map map = new HashMap();
Phone phone = new Phone(UUID.randomUUID().toString(), "华为", 8888);
/**
* 会根据重写后的hashCode值,经过位移计算,找到对应的位置,插入到里面
*/
map.put(phone, "val");
System.out.println("第一次获取 :" + map.get(phone));
/**
* 当改变对象里的属性的时候,重写后的hashCode值也随之改变,
* 当获取的时候已经不是上次所插入的位置了,所以获取的为null
*/
phone.setName("小米");
System.out.println("第二次获取 :" + map.get(phone));
3. 运行结果
由图可看出:
第一次获取时,是有值的,当改变其name属性在获取,就获取不到了。
这是因为当存储数据时会根据重写后的hashCode值,经过位移计算,找到对应的位置,插入到里面,当改变其name属性后,重写后的hashCode值也随之改变,获取的位置已经不是上次所插入的位置了,所以获取的为null
针对上面的问题,我们可以选择将不容易被改变的属性用来计算hashCode值
改造phone对象
public class Phone
private String serialNumber;
private String name;
private Integer price;
/**
* 只能根据编号serialNumber实例化对象,且serialNumber不可被更改,所以去掉其setSerialNumber方法
* @param serialNumber
*/
public Phone(String serialNumber)
this.serialNumber = serialNumber;
public String getSerialNumber()
return serialNumber;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Integer getPrice()
return price;
public void setPrice(Integer price)
this.price = price;
@Override
public String toString()
return "Phone" +
"serialNumber='" + serialNumber + '\\'' +
", name='" + name + '\\'' +
", price=" + price +
'';
/**
* 重写,
* 如果希望改变对象的属性,其对象的hash值不会发生变化
* 则需要以不容易被改变的属性用来计算hashCode值和重写equals方法
*
*/
@Override
public boolean equals(Object o)
if (this == o) return true;
if (!(o instanceof Phone)) return false;
Phone phone = (Phone) o;
return getSerialNumber().equals(phone.getSerialNumber()) ;
@Override
public int hashCode()
return Objects.hash(getSerialNumber());
将Phone 对象作为key放入map
public static void main(String[] args)
Map map = new HashMap();
Phone phone = new Phone(UUID.randomUUID().toString());
phone.setName("华为");
phone.setPrice(8888);
map.put(phone, "val");
System.out.println("第一次获取 :" + map.get(phone));
phone.setName("小米");
System.out.println("第二次获取 :" + map.get(phone));
运行结果
总结
- quals相同hashCode一定相同;
- hashCode相同equals不一定相同;
- hashCode不相同则对象一定不相同;
- hashCode相同则对象不一定相同;
- 对象相同,则hashCode一定相同;
- 对象不相同,则hashCode不一定相同;
- 所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准;
- hashCode方法判断的是对象的内存地址,不同对象地址一定不同。也可用==
- equals方法判断两个对象的值是否相等。
- 当把某个类的对象当成 HashMap的 key,或将这个类的对象放入 HashSet 中保存时,重写hashCode时尽量使用不可变的属性。
- 所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。
- 在HashSet添加对象的时候,会先判断hashCode是否一致,如果一致则再调用equals方法,判断内容是否一致。
- 如果自定义对象未重写 hashCode方法,则会使用父类Object的hashCode,Object的hashCode每次new一个对象就会有不同的hash值,如果不重写,即使相同的对象也能被添加。
- 即使重写了hashCode方法,当存储对象时也会有几率返回相同的hash值,也就是哈希碰撞,此时就需要通过equals方法来判断对象内容是否相同,相同:则不添加;不相同:则添加到相同索引下的链表。
以上是关于SpringBoot 重写hashCode方法和equals方法的主要内容,如果未能解决你的问题,请参考以下文章
为什么要重写equals()方法 和 hashCode()方法
JAVA中重写equals方法为啥要重写hashcode方法说明