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

标签 java hashmap

我发现一个很神奇的东西,简单的代码如下:

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

调用后

HashMap<String,String> map = new HashMap<String,String>();

the state of map object 字段变量entrySet不为null,即已初始化。

<小时/>

那么这是我的第一问题,entrySet何时初始化? 看起来相关代码应该在HashMap的构造中,但下面是这个构造函数的源代码

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

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

事情还在继续。 调用后

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

字段变量tableentrySet的内容如下图。 enter image description here 那么这是我的第二个问题:什么时候将这个值添加到entrySet中? 看起来应该是 put 方法实现这些东西。 下面是 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编写一个小工具来打印线程ID,该线程ID调用包java.util下面的类> 发现只有一个线程。

那我想念什么呢?调试过程中是否存在问题?希望我能清楚地描述我的问题,一切都会很感激。

添加:我的java版本是1.8.0_77,eclipse版本是4.6.14.5.1>

最佳答案

是你的调试器欺骗了你。调试器 View 调用 toString(),它实际上调用 entrySet()(请参阅 AbstractMap.toString())。这就是为什么当您查看时 entrySet 已经初始化了。

如果您通过反射实用程序查看那里,例如使用以下代码:

HashMap<String, String> 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 = []

如您所见:如果没有调用 toString() 并在其之后进行初始化,entrySet 实际上仍然是 null

这同样适用于你的第二个问题。如果您“反射(reflection)性地”查看这些值:

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

正如预期的那样,你会得到:

entrySet = null

关于java - HashMap 如何以及何时初始化 EntrySet 并向其中添加值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41714233/

相关文章:

java - 如何将 JButton 添加到 GridLayout?

java - 安全:http and properties (Spring Security)

java - 重复图层列表中的颜色背景

java - 从文本中找出一个单词的所有行号

java - ibatis中选择查询,以hashMap为parameterClass

java - 如何使用 Java 为 Windows 编写软件?

java - 通过对某些字段进行分组,将 java hashMap 转换为另一个 hashMap

java - HashMap JDK8 中的方法 putTreeVal()

java - 从 hashmap 的键对象中获取整数值

c++ - 如何在VS2005中使用sgi hash_table?