A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 第一印象 中级黑马   /  2013-8-29 18:17  /  3966 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 第一印象 于 2013-9-3 08:26 编辑

1.对于HashSet,Hashtable,HashMap这三个集合,他们存储元素的时候,都是根据hash算法来确定元素的位置的,当我 new HashMap()的时候,hash表有一个初始容量和默认的加载因子,对于HashMap,API中说默认初始容量是16,默认加载因子是0.75,也就是3/4,当hash表的3/4被填满时,hash表就会发生rehashing操作,那是不是可以说当我调用put方法往我的hashmap集合中添加了第十三条数据的时候(为什么是十三条的时候呢?因为12刚好16*0.75),这个hash表就发生rehashing操作了?就会对我已经存储到hashMap里面的所有值进行位置的重新分配?如果是的话,如果我在创建hashMap的时候,这么创建:
HashMap m = new HashMap(17);
初始容量为17,那这个怎么算呢?是从put第十三条数据开始rehashing还是第十四条呢?

2.对于rehashing的时候,hash表中桶的数量(也就是存储元素的位置的数量),会成倍的增加,这个具体增加多少倍,又是怎么算的呢?

评分

参与人数 1技术分 +1 收起 理由
黄文伯 + 1 赞一个!

查看全部评分

8 个回复

倒序浏览
亲,如问题已解决请将分类的“未解决”改为“已解决”。
以后的问题贴也要及时更改分类哦~
回复 使用道具 举报
哥们真是个技术牛人,研究得好仔细,既然是3/4的话,那即使你是17,它还是按3/4再取整吧,只是猜测
回复 使用道具 举报
{:soso_e179:}!研究得这么细,底层都被你给摸透了...
回复 使用道具 举报
straw 发表于 2013-8-29 22:45
!研究得这么细,底层都被你给摸透了...

呵呵,看了老毕的视频,再结合了李刚老师疯狂java的书籍细读了一下,还是觉得有疑问,所以希望在这里能够得到解决
回复 使用道具 举报
第一印象 发表于 2013-8-29 22:48
呵呵,看了老毕的视频,再结合了李刚老师疯狂java的书籍细读了一下,还是觉得有疑问,所以希望在这里能够 ...

为什么不是12而是13?我想只是当初设计这个集合的人的一句话的问题,他想在12这个位置触发rehashing动作也行或者定在13位置才触发也行,这对集合的性能没什么影响吧!
倒是你的第二个问题我想都没想过.
回复 使用道具 举报
straw 发表于 2013-8-29 23:00
为什么不是12而是13?我想只是当初设计这个集合的人的一句话的问题,他想在12这个位置触发rehashing动作也 ...

原来面试问到过类似的问题,问的是HashMap什么时候会内存溢出,由此想到可能跟这个有关系,但一直没解决过这个疑问
回复 使用道具 举报
可以看源码中怎么设计的。
  1. /**
  2.      * Rehashes the contents of this map into a new array with a
  3.      * larger capacity.  This method is called automatically when the
  4.      * number of keys in this map reaches its threshold.
  5.      *
  6.      * If current capacity is MAXIMUM_CAPACITY, this method does not
  7.      * resize the map, but sets threshold to Integer.MAX_VALUE.
  8.      * This has the effect of preventing future calls.
  9.      *
  10.      * @param newCapacity the new capacity, MUST be a power of two;
  11.      *        must be greater than current capacity unless current
  12.      *        capacity is MAXIMUM_CAPACITY (in which case value
  13.      *        is irrelevant).
  14.      */
  15.     void resize(int newCapacity) {
  16.         Entry[] oldTable = table;
  17.         int oldCapacity = oldTable.length;
  18.         if (oldCapacity == MAXIMUM_CAPACITY) {
  19.             threshold = Integer.MAX_VALUE;
  20.             return;
  21.         }

  22.         Entry[] newTable = new Entry[newCapacity];
  23.         boolean oldAltHashing = useAltHashing;
  24.         useAltHashing |= sun.misc.VM.isBooted() &&
  25.                 (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
  26.         boolean rehash = oldAltHashing ^ useAltHashing;
  27.         transfer(newTable, rehash);
  28.         table = newTable;
  29.         threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
  30.     }
复制代码
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
这句话很重要,是个阀值。超过这个阀值就会执行执行这句语句容量*加载因子,容量的默认是16,这个也可以自己设定初始值,自己设定的初始值要扩容还是容量*加载因子,加载因子还是0.75,因子不会变,根据容量来走。
  1. /**
  2.      * Adds a new entry with the specified key, value and hash code to
  3.      * the specified bucket.  It is the responsibility of this
  4.      * method to resize the table if appropriate.
  5.      *
  6.      * Subclass overrides this to alter the behavior of put method.
  7.      */
  8.     void addEntry(int hash, K key, V value, int bucketIndex) {
  9.         if ((size >= threshold) && (null != table[bucketIndex])) {
  10.             resize(2 * table.length);
  11.             hash = (null != key) ? hash(key) : 0;
  12.             bucketIndex = indexFor(hash, table.length);
  13.         }

  14.         createEntry(hash, key, value, bucketIndex);
  15.     }
复制代码
还有这个方法,resize(2 * table.length);数组扩大为原来的2倍。会比较消耗性能,由于是数组方面的增加容量的一个方法,所有性能跟内存消耗会有点大,最好是有个大概值来设定好初始值会比较好。
回复 使用道具 举报
sergio 发表于 2013-9-3 00:44
可以看源码中怎么设计的。threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
...

有道理
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马