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的操作等价于遍历链表,此时性能很差。

  • 相关阅读:
    HUST 1372 marshmallow
    HUST 1371 Emergency relief
    CodeForces 629D Babaei and Birthday Cake
    CodeForces 629C Famil Door and Brackets
    ZOJ 3872 Beauty of Array
    ZOJ 3870 Team Formation
    HDU 5631 Rikka with Graph
    HDU 5630 Rikka with Chess
    CodeForces 626D Jerry's Protest
    【POJ 1964】 City Game
  • 原文地址:https://www.cnblogs.com/java-spring/p/8876610.html
Copyright © 2011-2022 走看看