欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HashMap解惑

程序员文章站 2022-06-04 19:28:00
...

  点击上方HashMap解惑蓝字  中科软之java项目开发综合知识

本公众号主要推送javaweb开发相关技术,基础知识点,同时会深入剖析复杂的问题,分享一些优秀的框架,大型项目经验,当今最流行的Javaweb技术,热点科技新闻,招聘信息等等。点击上方的蓝字,这样您每天可以看到更多的java知识和资讯!完全是免费订阅,请放心关注。

原文连接:http://wely.iteye.com/blog/2334552

HashMap中有一些我们容易忽视的点

1. 关于key的hash和equals

Java代码  

1. public V put(K key, V value) {  

2.         if (table == EMPTY_TABLE) {  

3.             inflateTable(threshold);  

4.         }  

5.         if (key == null)  

6.             return putForNullKey(value);  

7.         int hash = hash(key);  

8.         int i = indexFor(hash, table.length);  

9.         for (Entry<K,V> e = table[i]; e != null; e = e.next) {  

10.            Object k;  

11.            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  

12.                V oldValue = e.value;  

13.                e.value = value;  

14.                e.recordAccess(this);  

15.                return oldValue;  

16.            }  

17.        }  

18.  

19.        modCount++;  

20.        addEntry(hash, key, value, i);  

21.        return null;  

22.    }  

 由上述代码知道,hash值是用来确定bucketIndex,equals是用来和链表上的值比较,因此对于key是自定义的类,强烈建议重写hashCode和equals方法。此处也是容易引起内存泄露的点。

下面摘抄一段JDK里面的注释,

Java代码  

1. /** 

2.      * Returns a hash code value for the object. This method is 

3.      * supported for the benefit of hash tables such as those provided by 

4.      * {@link java.util.HashMap}. 

5.      * <p> 

6.      * The general contract of {@code hashCode} is: 

7.      * <ul> 

8.      * <li>Whenever it is invoked on the same object more than once during 

9.      *     an execution of a Java application, the {@code hashCode} method 

10.     *     must consistently return the same integer, provided no information 

11.     *     used in {@code equals} comparisons on the object is modified. 

12.     *     This integer need not remain consistent from one execution of an 

13.     *     application to another execution of the same application. 

14.     * <li>If two objects are equal according to the {@code equals(Object)} 

15.     *     method, then calling the {@code hashCode} method on each of 

16.     *     the two objects must produce the same integer result. 

17.     * <li>It is <em>not</em> required that if two objects are unequal 

18.     *     according to the {@link java.lang.Object#equals(java.lang.Object)} 

19.     *     method, then calling the {@code hashCode} method on each of the 

20.     *     two objects must produce distinct integer results.  However, the 

21.     *     programmer should be aware that producing distinct integer results 

22.     *     for unequal objects may improve the performance of hash tables. 

23.     * </ul> 

24.     * <p> 

25.     * As much as is reasonably practical, the hashCode method defined by 

26.     * class {@code Object} does return distinct integers for distinct 

27.     * objects. (This is typically implemented by converting the internal 

28.     * address of the object into an integer, but this implementation 

29.     * technique is not required by the 

30.     * Java<font size="-2"><sup>TM</sup></font> programming language.) 

31.     * 

32.     * @return  a hash code value for this object. 

33.     * @see     java.lang.Object#equals(java.lang.Object) 

34.     * @see     java.lang.System#identityHashCode 

35.     */  

36.    public native int hashCode();  

 

 

2. rehash的条件

Java代码  

1. void addEntry(int hash, K key, V value, int bucketIndex) {  

2.         if ((size >= threshold) && (null != table[bucketIndex])) {  

3.             resize(2 * table.length);  

4.             hash = (null != key) ? hash(key) : 0;  

5.             bucketIndex = indexFor(hash, table.length);  

6.         }  

7.   

8.         createEntry(hash, key, value, bucketIndex);  

9.     }  

 if条件告诉我们rehash的条件要同时满足两个:map中元素个数不小于阀值即容量*负载因子,对应的bucketIndex处有元素。

 另外,如下代码作备忘,

Java代码  

1. static int indexFor(int h, int length) {  

2.         // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";  

3.         return h & (length-1);  

4.     }  

 

3. 可以插入(null, null)吗

Java代码  

1. Map<String, String> map = new HashMap<String, String>();  

2.         map.put(nullnull);  

3.         System.out.println(map.size()); // 1  

4.   

5. private V putForNullKey(V value) {  

6.         for (Entry<K,V> e = table[0]; e != null; e = e.next) {  

7.             if (e.key == null) {  

8.                 V oldValue = e.value;  

9.                 e.value = value;  

10.                e.recordAccess(this);  

11.                return oldValue;  

12.            }  

13.        }  

14.        modCount++;  

15.        addEntry(0, null, value, 0); // hash = 0, bucketIndex = 0  

16.        return null;  

17.    }  

注意,Hashtable和ConcurrentHashMap进行put时若value为null,将抛出NullPointerException。 

 

4. table默认初始大小 - 16

Java代码  

1. public HashMap(int initialCapacity, float loadFactor) {  

2.         // ...  

3.   

4.         this.loadFactor = loadFactor; // 0.75  

5.         threshold = initialCapacity; // 16  

6.         init(); // nothing  

7.     }  

8.   

9. public V put(K key, V value) {  

10.        if (table == EMPTY_TABLE) {  

11.            inflateTable(threshold);  

12.        }  

13.        // ...  

14.}  

15.  

16.private void inflateTable(int toSize) {  

17.        // Find a power of 2 >= toSize  

18.        int capacity = roundUpToPowerOf2(toSize); // 16  

19.  

20.        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);  

21.        table = new Entry[capacity];  

22.        initHashSeedAsNeeded(capacity);  

23.    }  

24.  

25.private static int roundUpToPowerOf2(int number) {  

26.        // assert number >= 0 : "number must be non-negative";  

27.        return number >= MAXIMUM_CAPACITY  

28.                ? MAXIMUM_CAPACITY  

29.                : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;  

30.    }  

 

5. 关于HashMap里的hash(Object key)方法

Java代码  

1. final int hash(Object k) {  

2.         int h = hashSeed;  

3.         if (0 != h && k instanceof String) {  

4.             return sun.misc.Hashing.stringHash32((String) k);  

5.         }  

6.   

7.         h ^= k.hashCode();  

8.   

9.         // This function ensures that hashCodes that differ only by  

10.        // constant multiples at each bit position have a bounded  

11.        // number of collisions (approximately 8 at default load factor).  

12.        h ^= (h >>> 20) ^ (h >>> 12);  

13.        return h ^ (h >>> 7) ^ (h >>> 4);  

14.    }  

15.  

16./** 

17.     * Initialize the hashing mask value. We defer initialization until we 

18.     * really need it. 

19.     */  

20.    final boolean initHashSeedAsNeeded(int capacity) {  

21.        boolean currentAltHashing = hashSeed != 0;  

22.        boolean useAltHashing = sun.misc.VM.isBooted() &&  

23.                (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);  

24.        boolean switching = currentAltHashing ^ useAltHashing;  

25.        if (switching) {  

26.            hashSeed = useAltHashing  

27.                ? sun.misc.Hashing.randomHashSeed(this)  

28.                : 0;  

29.        }  

30.        return switching;  

31.    }  

 

有人用微信聊天,有人却在微信中学习,成长。下面是2016最HOT公众号,赶快试试新的关注方法吧!


关注方式
★长按二维码,选择“识别图中二维码”进行关注。

HashMap解惑

HashMap解惑