1. 为什么重写equals必须重写hashCode?
因为重写equals和hashcode才能保证对象的唯一性。
* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
根据官方equals方法的注释:当equas方法被重写时,也要重写hashcode方法,以维护hashcode方法的一般约定。即相等的对象必须具有相等的哈希码。
2.为什么要保证对象的唯一性?使用场景有哪些?
我们在使用hashmap 等map形式的数据时,有时候要进行对象的判断,相同的属性意味着需求里的对象就是同一个对象。如:
public class User {
String name;
int code;
}
HashSet<User> users = new HashSet<>();
users.add(new User("lisi", 110));
users.add(new User("lisi", 110));
users.add(new User("ww", 111));
Iterator<User> iterator = users.iterator();
while(iterator.hasNext()){
User next = iterator.next();
System.out.println(next);
}
结果:
User{name='lisi', code=110}
User{name='lisi', code=110}
User{name='ww', code=111}
我们希望这两个lisi,只加入一个即可,因为在业务上,他们就是同一个人,没有必要加入两次。
加入集合的有两个相同的对象lisi,按照需求,相同的属性就是同一个对象,但是集合中依然两个属性一样的对象。这就违背了需求。
原因:
hashset无法判断他们是同一个对象导致。因为对象是否唯一,取决于equals 和hashcode的逻辑。因为没有重写,所以程序认为不是一个对象。
默认这种形式下,是否为同一个对象的判断使用的是object的equals和hashcode.查询源码
3.Object 源码 equals和hashcode
Object.class
//首先equals判断是对象之间的地址是否相同,大家知道,当执行new命令时,就会新建
//一个对象,产生一个新的内存地址。因此他们肯定不相同,所以程序认为不是一个对象。
public boolean equals(Object obj) {
return (this == obj);
}
//本地方法
/* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* 返回一个hash值,有利于支持哈希表,如hashmap
* /
//As far as is reasonably practicable, the {@code hashCode} method defined * by class {@code Object} returns distinct integers for distinct objects.
//合理可行的情况下,由类object的hashcode方法给不同的对象返回不同的整数。
public native int hashCode();
那这种形式是如何判断是否为同一个对象的呢?
4.判断对象是否相同
如果要解决上述问题,就要重写User对象的equals和hashcode方法
当重写了equals和hashcode方法时,当对象之间进行对比,
1.会先调用hashcode方法,它会根据对象的属性产生一个hash值,
2.在执行equals,先判断内存地址值是否相等,在判断是否为null,在判断属性是否相等。
还能够提高效率。当对象属性太多,equals就会臃肿,先判断hashcode,就可以避免无意义的执行。
如果hashcode不同,对象肯定不同。
如果hashcode相同,再去比较equas方法
@Override
public boolean equals(Object o) {
//如果两个对象内存地址相同,肯定为同一个对象。返回true
if (this == o) return true;
//如果对象为null 等,false
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
//对比对象之间的属性是否相同,返回状态
return code == user.code && name.equals(user.name);
}
/**
* 根据对象的属性产生hash值。
*/
@Override
public int hashCode() {
return Objects.hash(name, code);
}