面试题:
public class User { private String id; public User(String id) { this.id = id; } @Override public boolean equals(Object o) { if (this == o) { return true;} if (o == null || getClass() != o.getClass()) {return false;} User user = (User) o; return id != null ? id.equals(user.id) : user.id == null; } @Override public int hashCode() { return id != null ? id.hashCode() : 0; } public static void main(String[] args) { Set<User> set = new HashSet<>(); User u1 = new User("1"); User u2 = new User("1"); User u3 = new User("1"); set.add(u1); set.add(u2); set.add(u3); for (User u:set) { System.out.println(u.id); } } } //问题:当User只重写equals 或者 只重写hashcode ,以及同时重写后,当遍历Set结果是什么?
流程图说明:
那么当存入set 或者map 中的不允许相同数据存入的流程是怎样的呢?见下图
以上抛出几个问题
1、hashCode 为什么放在equals 之前?
equals 的比较是复杂的,重写该方法后,会进行null,空,是否是该对象等等比较,如果先进行hashCode 比较则提升性能,一旦不同即可放入对象
2、为什么既要进行hashCode 也要进行equals比较?
先抛老生常谈的结论:hashCode 值相同 equals 不一定相同,equals 相同,hashCode 一定相同。
方法介绍:
equals : 源码进行了==比较,比较地址!
hashCode : 通过hash算法计算一个int 值。计算地址!
原理理解:
hashCode 和 equals 都是Object 的方法,如果不重写都是对地址进行操作。
下面根据最上面的面试题来给出理解思路:(为方便讲解粘上部分代码)
User u1 = new User("1"); User u2 = new User("1"); User u3 = new User("1"); set.add(u1); set.add(u2); set.add(u3);
以下三种情况讲解:
一、不重写hashCode,重写equals:根据流程图 第一步执行hashCode 的判断 由于没有重写hashCode所以对地址进行hash计算 两个对象地址不同直接存入集合。 遍历结果: 1, 1 , 1
二、不重写equals,重写hashCode :第一步执行hashCode值相同,往下执行equals 由于未重写equals 所以直接比较地址,两个对象地址不同,直接存入Set集合。 遍历结果: 1, 1 , 1
三、同时重写:第一步执行hashCode,值相同,往下执行equals ,重写equals 判断对象相同,舍弃。 遍历结果: 1