【源码分析】HashMap的数据结构

之前有研究Java源码中HashMap的put()方法的实现,后来又看了HashMap的整体数据结构,记录一下

什么是HashMap

经常用到HashMap,用来存储数据,在某些框架中可以替代javabean,主要特点如下:

  • key-value形式的键值对
  • 非线程安全的
  • 存储数据的数据和插入顺序无关
  • key可以为null

其中和HashMap差不多但是是线程安全并且key不能为null的类是HashTable,但是很少用,一般都是用ConcurrentHashMap.

内部结构

我们都知道HashMap内部都是一组组键值对,那么这个键值对在内部是什么形式存在的呢?
其实是 Node[] ,即节点数组的形式保存.就是说HashMap其实是一个数组,每一个存进去的键值对是数组中的一个元素.
那么有几个问题.

  • 我new一个HashMap的时候并没有指定这个”数组”的大小

查看源码可以知道,刚new出来的时候HashMap并没有设置容量,是在调用put()方法的时候检查,如果这个HashMap的table,即Node[]数组是null,那么初始化一下,经过一系列的方法产生一个有默认容量( DEFAULT_INITIAL_CAPACITY=16 )的Node[]数组

  • 我一直放键值对没有出现数组下标越界的异常啊

因为HashMap中有一个常量叫加载因子( DEFAULT_LOAD_FACTOR=0.75 ),当当前元素的数量占容量的百分比大于动态因子的时候,就会进行数组的自动扩容,这是自动维护的,所以没有感觉

  • Node是什么

还记得HashMap的遍历吗?

Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
for (Entry<String, String> entry : map.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();
}

HashMap的遍历可以看出,里面的键值对是以Entry的形式存在,那么Node和Entry什么关系?
其实,Entry是Map接口中的内部接口Entry,而Node是Entry的实现类.

  • 那么键值对是怎么放入HashMap中的

我们都知道,放入数组需要指定下标.那么这个下标是什么?在HashMap中是和这个键的hash值有关,在hash值经过某种算法后得到的下标,然后将键值对放入数组中

  • 如果键的hash值重复了怎么办?

在插入的时候,我们知道同一个键插入不同的值时,会用新的值替换旧的值,并将旧的值返回.但是,有时候会出现不同的键得到相同的hash值,这个就尴尬了,那么内部是怎么解决的.

这个我们可以看一下Node类的成员变量

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    fianl K key;
    V value;
    Node<K, V> next;
    ...
}

重点是这个next是一个新的Node,这是什么,这是链表啊!也就是说,出现这种情况了,那么会在Node[]的一个位置放着一个链表,里面是重复的hash值的Node.
ps:如果链表过长,则会转化成HashMap内部的红黑树TreeNode,这样可以提高性能


以上就是HashMap的简单介绍,可能有什么问题,发现了记得评论,谢谢.有什么新的想法会不定期更新…

猜你喜欢

转载自blog.csdn.net/coldfireman/article/details/77484704