HashMap工作原理问题求解

铁衣 2015-02-02 10:50:16
最近我在研究Map集合的工作原理,以便做些优化。
首先看的是HashMap。

写一行初始化HashMap的代码:(debug模式)
Map<String, String> map = new HashMap<String, String>(3, 0.75f);
map.put("a","第1个元素");

我分别在HashMap的构造方法、put方法里加了断点。
执行结果居然是先进入put方法,执行了好几次后,才进入构造方法。。。
而且进入put方法时,阀值显示的是12。
我设置的初始化容量是3,阀值应该是3 * 0.75才对。
put方法被执行了大概十几次,然后才进入构造方法。

构造方法还没执行,对象实例都还没创建,怎么能直接执行put方法呢?
为什么会这样,谁知道吗?
...全文
329 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
疯狂熊猫人 2015-02-02
  • 打赏
  • 举报
回复
1、初始化一个固定大小的数组用以存放对象 2、put对象的时候,首先判断数组是否已满,已满则重新创建一个更大的数组,并复制原数字中的对象到新数组,根据key计算其hash值,然后再对hash进行散列,用散列值&数组长度,求出该key应该存放在数组中的位置,将对象放入。
铁衣 2015-02-02
  • 打赏
  • 举报
回复
引用 1 楼 qq840727854 的回复:
map.put("a","第1个元素"); 打个断点 f5 step into
这里断点打了。 我再详细描述一下执行过程。 Map<String, String> map = new HashMap<String, String>(3, 0.75f); map.put("a","第1个元素"); 断点3处: 1、map.put("a","第1个元素");前加1个。 2、构造方法里1个。 3、put方法里1个。 断电顺序是:3-->2-->1 也就是说,一开始执行的put方法不是我写的这个put。 我自己写的put方法确实是在构造函数之后的。 那么,执行构造函数之前的put方法的调用者是谁,目的是什么?
qq840727854 2015-02-02
  • 打赏
  • 举报
回复
map.put("a","第1个元素"); 打个断点 f5 step into
铁衣 2015-02-02
  • 打赏
  • 举报
回复
引用 6 楼 rumlee 的回复:
这个先进入put方法,实际上执行的却不是你的这次调用,而是在其它类中被调用的。 在系统的classloader中就用了hashmap,所以jvm在加载你的class的时候就已经使用到了hashmap了,所以出现这种结果就没有什么好奇怪了。
你说的对,可能是我想多了。 jvm在加载我的class的时候。估计不仅用到了HashMap,也许还用到了ArrayList。 其实就是JVM为了实现某个目的对HashMap的一次调用而已。
rumlee 2015-02-02
  • 打赏
  • 举报
回复
这个先进入put方法,实际上执行的却不是你的这次调用,而是在其它类中被调用的。 在系统的classloader中就用了hashmap,所以jvm在加载你的class的时候就已经使用到了hashmap了,所以出现这种结果就没有什么好奇怪了。
铁衣 2015-02-02
  • 打赏
  • 举报
回复
没有人可以帮我解答一下吗? 是我的描述不够清楚吗? 我在main方法里写了两行代码: Map<String, String> map = new HashMap<String, String>(3, 0.75f); map.put("a", "第1个元素"); 我设置的初始容量为3,负载因子为0.75f。 1、在map.put("a", "第1个元素");这一行加了一个断点。 2、在HashMap的带参构造函数 public HashMap(int initialCapacity, float loadFactor) 的第1行加了一个断点。 3、在put方法内部(源码)的第1行加了一个断点。 然后我执行main方法(debug模式)。 我预想的断点执行顺序应该是:先进入第2个断点位置-->再进入第1个断点位置-->最后进入第3个断点位置。 实际的执行顺序是:第3个断点位置-->第2个断点位置-->第1个断点位置-->第3个断点位置 第3个断点位置进入了两次。 也就是说在构造方法执行之前,put方法就已经被调用了。 这一点让我很迷茫。 我仔细看了一下第一次进入第3断点位置时的运行时个参数的值。 发现数组初始化长度是默认的16,并非我设置的3。 当然,阀值也不是我想要的3*0.75,而是16*0.75=12。 put方法被执行了12次,存入的value值是“file:///D:/JDK/jdk1.7.0_55/jre/lib/ext/access-bridge-64.jar=sun.misc.URLClassPath$JarLoader@58e4d7f7,”这种形式的。 12次执行完之后,这才进入第2个断点(构造方法)。 然后进入第1个断点,最后又进入第3个断点。 最后这次进入第3个断点时,我也分析了运行时参数。 这时,初始化容量与阀值都是跟我设置的一致的。 也就是说,在初始化我的实例之前,JVM自己初始化了一个长度为16的HashMap实例。 而且往这个实例插入了一些奇怪的数据,就是我上面说的那些内容。 然后才会来执行我写的代码。 请问JVM做这个事情的目的是什么? 希望有人能帮我解答一下,非常感谢!
铁衣 2015-02-02
  • 打赏
  • 举报
回复
引用 3 楼 crazypandariy 的回复:
1、初始化一个固定大小的数组用以存放对象 2、put对象的时候,首先判断数组是否已满,已满则重新创建一个更大的数组,并复制原数字中的对象到新数组,根据key计算其hash值,然后再对hash进行散列,用散列值&数组长度,求出该key应该存放在数组中的位置,将对象放入。
你可能没有看清楚我碰到的问题。 我想知道的是,为什么在HashMap的构造方法被执行之前,就先执行put方法了。

62,621

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧