当前位置:  开发笔记 > 编程语言 > 正文

HashMap如何以及何时初始化entrySet并向其中添加值

如何解决《HashMap如何以及何时初始化entrySet并向其中添加值》经验,为你挑选了1个好方法。

我找到了一个非常神奇的东西,简单的代码如下:

public class Demo{
    public static void main(String[] args){
        HashMap map = new HashMap();
        map.put("a", "aa");
        System.out.println("end");
    }
}

在调用之后

HashMap map = new HashMap();

地图对象的状态 字段变量entrySet不为null,也就是说它已经初始化.


那么这是我的第一个问题,什么时候初始化了entrySet?似乎相关的代码应该在HashMap的构造中,但下面是这个构造函数的源代码

 public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

它似乎不存在初始化entrySet的代码.

事情还在继续.在调用之后

map.put("a","aa")

字段变量entrySet的内容如下图所示. 在此输入图像描述 那么这是我的第二个问题:将此值添加到entrySet中时?似乎应该是put方法实现这些东西.以下是方法.

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

它调用putVal方法,下面是putVal的一些代码

final V putVal(...) {
    ....
    tab[i] = newNode(hash, key, value, null);
    ....
    ++modCount;//after invoke this the entrySet is still empty
    if (++size > threshold)
        resize();//this has not been executed
    afterNodeInsertion(evict);//I debug several times, sometimes before invoke this the entrySet has an Element and sometimes
    return null;
}    

在调用之后

 ++modCount;

在调用之前,entrySet为空

 afterNodeInsertion(evict);

entrySet有一个元素.但似乎这两行之间的代码与entrySet没有任何关系.我想也许有几个线程操作entrySet然后我用jvm_ti编写一个小工具来打印threadID,它调用java.util包下面的类,发现只有一个线程.

那我想念的是什么?调试过程中是否存在问题?希望我清楚地描述我的问题,一切都会被欣赏.

add: 我的java版本是1.8.0_77,eclipse版本是4.6.14.5.1



1> Roland..:

是你的调试器愚弄你.调试器视图调用toString()实际调用的内容entrySet()(请参阅参考资料AbstractMap.toString()).这就是为什么entrySet当你看到它时已经初始化了.

如果你通过反射工具查看,例如使用以下代码:

HashMap map = new HashMap<>();

Field entrySetField = HashMap.class.getDeclaredField("entrySet");
entrySetField.setAccessible(true);
Object entrySet = entrySetField.get(map);
System.out.println("entrySet = " + entrySet);
System.out.println("map.toString() = " + map.toString());
entrySet = entrySetField.get(map);
System.out.println("entrySet = " + entrySet);

你得到以下输出:

entrySet = null
map.toString() = {}
entrySet = []

正如您所看到的那样:null如果没有toString()被调用并且在它之后被初始化,则实际上仍然是entrySet .

这同样适用于您的第二个问题.如果你"反思地"看待这些值:

// Starting from where my entrySet is still null
map.put("key", "value");
entrySet = entrySetField.get(map);
System.out.println("entrySet = " + entrySet);

你得到了,如预期的那样:

entrySet = null

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有