• 原始的equals是比较两个对象的地址,而hashCode也是由地址构造来的。
  • 重写equals方法并改变其中比较的参数时,hashCode也应该改变。
  • 如果根据equals方法,两个对象是一样的,那么它们的hashCode也应该一样。
  • 如果两个对象不相等,hashCode不强制要求不一样,但是能不一样更好。
  • 以下代码是一个手机号码的例子,手机号码由区号和本地手机号构成。我们重写了equals方法,但没有重写hashCode。

    public class TantanitReaderPhone {
        private String areaCode;
        private String localNumber;
    
        public TantanitReaderPhone(String areaCode, String localNumber) {
            this.areaCode = areaCode;
            this.localNumber = localNumber;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            TantanitReaderPhone that = (TantanitReaderPhone) o;
            //区号、号码都相同即为相同
            return Objects.equals(areaCode, that.areaCode) &&
                    Objects.equals(localNumber, that.localNumber);
        }
    
        @Override
        public int hashCode() {
            return super.hashCode();
        }
    }
    
  • 以下测试代码定义了一个以TantanitReaderPhone为key的HashMap。我们在保存和取出时,分别都new了一个对象,这两个对象有着相同的areaCode和localNumber,根据我们重写的equals方法,它们是相等的。但是由于我们没有重写hashCode方法,导致get()时调用hashCode方法获取hashCode来定位时得到这两个对象的哈希值不同,所以第二个对象无法再HashMap里面找到第一次存进去的值。

    Map<TantanitReaderPhone,String> map=new HashMap<>();
    map.put(new TantanitReaderPhone("86","13200001234"),"张三");
    //取不出来
    map.get(new TantanitReaderPhone("86","13200001234"));
    
  • 因此,hashCode方法应该包含equals中所有字段,而不能包含没有的字段,可能导致相等的对象有不同哈希值。比如,String的hashCode是根据每一个字符来构造的,而本例中的hashCode():

    @Override
    public int hashCode() {
        int result=17;
        //若areaCode、localNumber两个字符串分别相同则返回hashCode相同
        result=31*result+areaCode.hashCode();
        result=31*result+localNumber.hashCode();
        return result;
    }