• 覆盖equals时总要覆盖hashCode


    在每个覆盖了equals方法的类中,必须覆盖hashCode方法,否则导致该类无法结合基于散列的集合一起正常工作,这些集合包括HashMap,HashSet,HashTable(废弃)

    Object规范:1,在应用程序执行期间,只要对象的equals方法比较的操作用到的信息没有被修改,那么对同一个对象调用多次HashCode方法都必须始终返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的的整数可以不一致。

    2,如果两个对象根据equals方法比较是相等的,那么调用两个对象的中任意一个对象的hashCode方法都必须产生相同的整数结果。

    3,如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个hashCode方法,则不一定要产生相同的整数结果。但是应该知道,给不相同的对象产生截然不同的整数结果,有可能提高散列表的性能。

    根据类的equals方法,两个截然不同的实例在逻辑上有可能是相等的但是根据Object类的HashCode方法,他们仅仅是两个没有任何相同之处的对象。因此对象的hashCode方法返回两个看起来是随机的整数,而不是根据第二个约定所要求的那样,返回两个相等的整数。

    为不相等的对象产生不相等的散列码

    /**
     * @Description
     * @Author liam661
     * @Date 2021/4/19 21:30
     **/
    public final class PhoneNumber {
        private final short areaCode;
        private final short prefix;
        private final short lineNumber;
    
        public PhoneNumber(int areaCode,int prefix, int lineNumber){
            rangeCheck(areaCode,999,"area code");
            rangeCheck(prefix,999,"prefix");
            rangeCheck(lineNumber,9999,"line number");
            this.areaCode = (short) areaCode;
            this.prefix = (short) prefix;
            this.lineNumber = (short) lineNumber;
        }
        private static void rangeCheck(int arg,int max,String name){
            if(arg < 0 || arg > max ){
                throw new IllegalArgumentException(name +": "+ arg);
            }
        }
        @Override
        public boolean equals(Object o){
            if(o == this)
                return true;
            if(!(o instanceof  PhoneNumber)){
                return false;
            }
            PhoneNumber pn = (PhoneNumber) o;
            return pn.lineNumber == lineNumber && pn.prefix == prefix && pn.areaCode == areaCode;
        }
        public static void main(String [] args){
            PhoneNumber p1 = new PhoneNumber(77,867,5309);
            PhoneNumber p2 = new PhoneNumber(77,867,5309);
            Map<PhoneNumber,String> m = new HashMap<PhoneNumber,String>();
            m.put(p1,"jeeny");
            m.put(p2,"lining");
            Set<PhoneNumber> set = new HashSet<PhoneNumber>();
            set.add(p1);
            set.add(p2);
            System.out.println(m.get(p1));
            System.out.println(m.get(p2));
            System.out.println(set);
        }
    }
    null
    [liam.mon4.PhoneNumber@2437c6dc, liam.mon4.PhoneNumber@6ed3ef1]

    由于PhoneNumber类覆盖hashCode方法,从而导致两个相同的实例具有不相同的散列码,违反了hashCode的约定

     @Override
        public int hashCode(){
            int result = 17;
            result = 31 * result + areaCode;
            result = 31 * result + prefix;
            result = 31 * result + lineNumber;
            return result;
        }
    lining
    [liam.mon4.PhoneNumber@95916]

    如果一个类是不变的,并且计算散列码的开销也很大,就应该考虑把散列码缓存在对象内部,而不是每次请求的时候都重新计算散列码。

    @Override
        private volatile int hashCode;
        public int hashCode(){
            int result = hashCode;
            if(result == 0){
                result = 31 * result + areaCode;
                result = 31 * result + prefix;
                result = 31 * result + lineNumber;
                hashCode = result;
            }
            return result;
        }

    但是不能产生最新的散列函数。

    不要试图从散列码计算中排除掉一个对象的的关键部分来提高性能。

    摘抄自《effective java 2》

  • 相关阅读:
    SentiAnalysis
    大数据索引技术 B+ tree vs LSM tree
    Regression, 回归问题
    Data Mining with R
    Why Vector Clock are Easy or Hard?
    How to know what an HRESULT code means?
    如何判断数据库表的某个列上有重复值的记录存在?
    关于SharePoint 2010里Servers in farm页面里status意义的澄清
    SharePoint Security系列 之二 CrossSite Request Forgery
    从MOSS2007升级到SharePoint2010后Report Server content types升级失败
  • 原文地址:https://www.cnblogs.com/changlili/p/14678975.html
Copyright © 2020-2023  润新知