zoukankan      html  css  js  c++  java
  • 覆盖equals的时候总要覆盖hashCode

    import java.util.HashMap;
    
    
    public class Student {
    
        private String name ;
        
        private String id;
        
        public Student(String name , String id) {
            this.id = id;
            this.name = name;
        }
        
        public String getName() {
            return this.name;
        }
        
        public String getId() {
            return this.id;
        }
        
        @Override
        public boolean equals(Object o) {
            if(o==this)
                return true;
            if(!(o instanceof Student)) 
                return false;
            
            Student t = (Student)o;
            if(!name.equals(t.getName())) 
                return false;
            if(!id.equals(t.getId()))
                return false;
            return true;
        }
        
        public static void main(String[] args) {
            HashMap<Student , Integer> map = new HashMap<Student, Integer>();
            Student t1 = new Student("s1","1");
            Student t2 = new Student("s1","1");
            System.out.println(t1.equals(t2));
            map.put(t1, 1);
            map.put(t2, 1);
            System.out.println(map.size());
        }
        
    }

    运行结果
    true
    2

    从上面运行 的结果就可以看到,虽然两个对象是“相等的”,但是map中却存放着两个值,这与map中key值唯一似乎的矛盾的,这个出现这个原因就是没有重写hashCode()方法,两个对象的散列码不一样,map在处理的时候就当做不同的对象来处理。---(因为hashcode不一样,那么认为equals方法也为false),如果如下所示,重写hashCode()方法,则只有一个值

    @Override
        public int hashCode() {
            int result = 17;
            int c = 0;
            c = this.name.hashCode();
            result = 31 * result+c;
            c= this.id.hashCode();
            result = 31*result+c;
            return result;
        }

    在Object规范中,有如下内容:

    1) 只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一的返回同一个整数。在一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。 
    2)如果连个对象根绝equals方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。 

    3)如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定产生不同的整数结果。

    如果覆盖equals时没有覆盖hashCode方法,则违反了约定的第二条。

    一个好的hashCode函数通常倾向于“为不相等的对象产生不相等的散列码”,这正是hashCode约定中第三条的意义。

    一个比较好的生成hashCode函数的方法如下:

    1、把某个非零常数值,比如说17,保存在一个叫result 的int 类型的变量值中。

    2、对于对象中的每一个关键域f (指equals 方法中考虑的每一个域,非equals用到的域一概不要考虑),完成以下步骤:

    • a 为该域计算int 类型的散列码c:
      • i如果该域是boolean 类型,则计算(f ? 1 : 0);
      • ii如果该域是byte、char、short 或者int 类型,则计算(int)f;
      • iii如果该域是long 类型,则计算(int)(f ^ (f >>> 32));
      • iv如果该域是float 类型,则计算Float.floatToIntBits(f);
      • v如果该域是double 类型,则计算Double.doubleToLongBits(f) 得到一个long 类型的值,然后按照步骤2.a.iii 对该long 类型计算散列值;
      • vi如果该域是一个对象引用,并且该类的equals 方法通过递归调用equals 的方式来比较这个域,则同样对这个域递归调用hashCode 方法;如果要求一个更为复杂的比较,则为这个域计算一个“规范表示”,然后针对这个规范表示调用hashCode。如果这个域的值为null,则返回0;
      • vii如果该域是一个数组,则把每一个元素当做单独的域来处理。然后根据步骤2.b 中的做法把这些散列值组合起来。
    • b 按照下面的公式,把步骤a 中计算得到的散列码c 组合到result 中:
      result = 31 * result + c;

    3、返回result 值。

    注:根据实践经验,在对ASCII 串的散列函数中,31 和37 是很好的散列因子。

    注意:必须排除equals方法没有用到的任何域。也不要试图从散列码中排除掉一个对象的关键部分来提高性能。

    如果一个类是不可变的,并且计算散列值的代价也比较大,那么就没有必要每次都计算了,应该考虑把散列码缓存在对象内部。

  • 相关阅读:
    js添加删除元素内容
    [H5]range对象的createRange方法
    [H5]range对象的clone方法
    [H5]range对象的setStart/setEnd方法
    [H5]range对象之selectNode等方法
    [H5]API之range对象
    上传本地Jar包到阿里云的云效私有仓库
    Alibaba Cloud Toolkit 一键部署插件使用入门
    关于mybatis 注意
    win10 docker 安装oracel11g
  • 原文地址:https://www.cnblogs.com/chenfei0801/p/3295533.html
Copyright © 2011-2022 走看看