zoukankan      html  css  js  c++  java
  • hashCode()方法对HashMap的性能影响

    HashMap的put()方法会比较key的hash值,key的hash值获取方式如下:

    //HashMap的put方法
        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
        //先获取key的hash值,如果key为null则hash值为0;如果key不为null,则获取key的hashCode值赋给h,然后求出h的(h向右移16位)次方,作为key的hash值
        static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }
        /**
         * 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}.
         */
        public native int hashCode();

    可以看到,最后调用的还是hashCode()方法

    实现一个好的hashCode()方法,能够尽可能地减少冲突,性能就会大大提高,下面举个栗子:

    创建一个对象,让它重写hashCode方法,返回固定的值1

    public class TestObject {
        public String name;
    
        @Override
        public int hashCode() {
            return 1;
        }
    
        public TestObject(String name) {
            this.name = name;
        }
    }

    然后创建10000个对象存入hashMap中,并用get方法取出来,计算耗时

    public class Test {
    
        public static void main(String[] args) {
            HashMap<TestObject, String> hashMap = new HashMap<>();
            long currentTimeMillis = System.currentTimeMillis();
            for (int i = 0; i < 10000; i++) {
                TestObject testObject1 = new TestObject("zhangsan");
                hashMap.put(testObject1, "abc");
            }
            for (TestObject testObject : hashMap.keySet()) {
                hashMap.get(testObject);
            }
            System.out.println(System.currentTimeMillis() - currentTimeMillis);
        }
    
    }

    输出结果为:

    1616

    也就是一千多ms

    如果不重写HashCode方法,用自己默认的hashCode方法

    public class TestObject {
        public String name;
    
        public TestObject(String name) {
            this.name = name;
        }
    }

    再次运行,输出结果为:

    6

    几毫秒左右

    另外说一下,发生冲突后数据的存放问题:

    当put()操作有冲突时,新的Entry依然会被安放在对应的索引下标内,并替换原有的值。同时,
    为了保证旧值不丢失,会将新的Entry的next指向旧值。这便实现了在一个数组索引空间内,存放多个值项。
    此时,HashMap实际上是一个链表的数组。
    如果hashCode()或者hash()方法实现较差,在大量冲突产生的情况下,HashMap事实上就退化为几个链表,对HashMap的操作等价于遍历链表,此时性能很差。

  • 相关阅读:
    EXE、DLL和OCX文件的最佳压缩工具ASPack
    mysql忘记帐号密码 解决办法。
    vs2010 C++ 静态编译(解决:程序在别人的机子运行不了,缺少mfc100.dll, xxx100d.dll等的解决方法)
    去掉word每个标题前都有个小黑点 附word2003与2007方法
    struts2 中jsp页面replace的使用
    struts2 改变portlet windowState
    .net 知识补充 注意点
    广义表(1)
    字符串匹配(kmp)
    二叉排序树
  • 原文地址:https://www.cnblogs.com/java-spring/p/8876610.html
Copyright © 2011-2022 走看看