1、为什么要重写equals方法
参考java中使用==进行比较,比较的是什么内容?
2、为什么要重写hashCode方法
判断2个对象是否相等我们常用的是调用对象的equals方法,所以重写了equals方法不就够用了吗?为啥还要重写hashCode方法?原因是在某些地方,判断2个对象相等是hashCode和equals一起判断的,如HashMap。
简单了解下HashMap的存储方式:
(1)HashMap底层是以数组方式进行存储的。
(2)将key-value键值对作为数组的一个元素进行存储。
(3)key-value都是Map.Entry中的属性。其中将key的值进行hash之后进行存储,即每一个key都是计算hash值,然后再存储。每一个hash值对应一个数组下标,数组下标是根据hash值和数组长度计算得来的。
(4)由于不同的key值可能具有相同的hash值,即一个数组的某个位置出现两个相同的元素,对于这种情况,HashMap采用链表的形式进行存储。即使用链地址法来解决冲突问题。
所以,在HashMap中,如果key的对象没有重写hashCode的话,2个我们认为是一样的对象因为hash计算出来的值是不一样的,所以在HashMap中他会被人为是2个不同的key。
3、hashCode方法和equals方法默认实现是什么?
Java对象默认是继承Object的,所以不重写默认使用的是Object对象的hashCode方法和equals方法,查看Object对象源码:
public native int hashCode();
hashCode有native标识,他是一个jni的方法,所以他的实现是外部实现,可能不同的操作系统会有不同的实现,具体不深入。
public boolean equals(Object obj) {
return (this == obj);
}
equals默认直接对比对象的内存地址。
4、那么如果不重写hashCode方法和equals方法会怎么样呢?我们这里举个简单的代码例子。
Book对象代码(我们认为在业务上,只要书名一致就认为对象是相等的,不管价格跟出售平台)
@Data
@ToString
public class Book {
/**
* 书名
*/
private String name;
/**
* 价格
*/
private String price;
/**
* 出售平台
*/
private String seller;
public Book(String name, String price, String seller) {
this.name = name;
this.price = price;
this.seller = seller;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
return Objects.equals(name, book.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
测试代码(我们简单的使用map的key为书,value为作者来进行测试)
public class Test {
public static void main(String[] args) {
Book book1 = new Book("Java编程思想","100","淘宝");
Book book2 = new Book("Java编程思想","110","京东");
System.out.println("equals()\t\t\t\t\t"+book1.equals(book2));
System.out.println("book1.getName().hashCode()\t"+book1.getName().hashCode());
System.out.println("book2.getName().hashCode()\t"+book2.getName().hashCode());
System.out.println("book1.hashCode()\t\t\t"+book1.hashCode());
System.out.println("book2.hashCode()\t\t\t"+book2.hashCode());
Map<Book, String> map = new HashMap<>();
System.out.println("\nmap为 书名->作家 映射 执行map.put(book1, \"Bruce Eckel\");");
map.put(book1, "Bruce Eckel");
System.out.println("map.get(book1)\t\t\t\t"+map.get(book1));
System.out.println("map.get(book2)\t\t\t\t"+map.get(book2));
}
}
hashCode和equals都重写的执行结果
equals() true
book1.getName().hashCode() 480343597
book2.getName().hashCode() 480343597
book1.hashCode() 480343628
book2.hashCode() 480343628
map为 书名->作家 映射 执行map.put(book1, "Bruce Eckel");
map.get(book1) Bruce Eckel
map.get(book2) Bruce Eckel
注释掉Book对象中的hashCode方法,即只重写了equals方法的执行结果
equals() true
book1.getName().hashCode() 480343597
book2.getName().hashCode() 480343597
book1.hashCode() 752848266
book2.hashCode() 815033865
map为 书名->作家 映射 执行map.put(book1, "Bruce Eckel");
map.get(book1) Bruce Eckel
map.get(book2) null
注释掉Book对象中的equals方法,即只重写了hashCode方法的执行结果
equals() false
book1.getName().hashCode() 480343597
book2.getName().hashCode() 480343597
book1.hashCode() 480343628
book2.hashCode() 480343628
map为 书名->作家 映射 执行map.put(book1, "Bruce Eckel");
map.get(book1) Bruce Eckel
map.get(book2) null
注释掉Book对象中的hashCode和equals方法的执行结果
equals() false
book1.getName().hashCode() 480343597
book2.getName().hashCode() 480343597
book1.hashCode() 1337752440
book2.hashCode() 1337503432
map为 书名->作家 映射 执行map.put(book1, "Bruce Eckel");
map.get(book1) Bruce Eckel
map.get(book2) null
参考资料:
https://blog.csdn.net/linjiaen20/article/details/82762933
https://developer.51cto.com/art/201908/601406.htm