Java集合框架 Map接口实现类--HashMap源码分析 & HasmMap与HashSet的关系 & HashTable & Properties(HashTable 的

Posted Z && Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java集合框架 Map接口实现类--HashMap源码分析 & HasmMap与HashSet的关系 & HashTable & Properties(HashTable 的相关的知识,希望对你有一定的参考价值。

Map接口实现类:

1. HashMap源码分析


HashMap的数组table存储的就是一个个的Node<K,V>类型,很清晰地看到有一对键值,还有一个指向next的指针:

HashMap的无参构造方法,进入到该构造方法的源码查看一下:

  • 发现没什么内容,只是赋值了一个默认加载因子;而在上文我们观察到源码中table和size都没有赋予初始值,说明刚创建的HashMap对象没有分配容量,并不拥有默认的16个空间大小,这样做的目的是为了节约空间,此时table为null,size为0。

当我们往map里添加元素时调用put方法:


  • 这里面创建了一个tab数组和一个Node变量p,第一个if实际是判断table是否为空,而我们现在只关注刚创建HashMap对象时的状态,此时tab和table都为空,满足条件,执行内部代码,这条代码其实就是把resize()所返回的结果赋给tab,n就是tab的长度,resize顾名思义就是重新调整大小。查看resize()源码(部分)
final Node<K,V>[] resize() {
      Node<K,V>[] oldTab = table;
      int oldCap = (oldTab == null) ? 0 : oldTab.length;
      int oldThr = threshold;
      if (oldCap > 0);
      else if (oldThr > 0);
      else {               // zero initial threshold signifies using defaults
          newCap = DEFAULT_INITIAL_CAPACITY;
          newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
      } 
      @SuppressWarnings({"rawtypes","unchecked"})
      Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
      table = newTab;
      return newTab;
  }
  • 该方法首先把table及其长度赋值给oldTab和oldCap;threshold是阈值的意思,此时为0,所以前两个if先不管,最后else里newCap的值为默认初始化容量16;往下创建了一个newCap大小的数组并将其赋给了table,刚创建的HashMap对象就在这里获得了初始容量。然后我们再回到putVal方法,第二个if就是根据哈希码得到的tab中的一个位置是否为空,为空便直接添加元素,此时数组中无元素所以直接添加。至此HashMap对象就完成了第一个元素的添加。当添加的元素超过16*0.75=12时,就会进行扩容
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict){
      if (++size > threshold)
          resize();
  }
  • 扩容的代码如下(部分):
final Node<K,V>[] resize() {
      int oldCap = (oldTab == null) ? 0 : oldTab.length;
      int newCap;
      if (oldCap > 0) {
          if (oldCap >= MAXIMUM_CAPACITY) {//略}
          else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                   oldCap >= DEFAULT_INITIAL_CAPACITY)
      }
  }
  • 核心部分是else if里的移位操作,也就是说每次扩容都是原来大小的两倍
  • 注:额外说明的一点是在JDK1.8以前链表是头插入,jdk1.8及以后链表是尾插入。

小结:

  • HashMap刚创建时,table是null,这么做是为了节省空间。当添加第一个元素时,table的容量会调整为16
  • 当元素个数大于阈值(16 * 0.75 = 12 )时,会进行扩容,扩容的大小是原来的2倍。这么做的目的是为了减少调整扩容的次数,提升运行效率。
  • jkd1.8 当链表长度大于等于8,并且元素个数大于等于64时,链表会调整成为红黑树,目的是提高执行效率。
  • jkd1.8 链表元素个数小于等于6时,红黑树结构还原成链表。
  • jdk1.8以前,链表时采用头插法,jdk1.8及以后以后采用尾插法。


2. HasmMap与HashSet的关系

  • 点进去HashSet的构造方法,我们发现HashSet就是用HashMap实现的:

  • 点进去HashSet的put方法,发现就是用的map的put方法(用map的key来保存数据):


3. HashTable

api文档:


4. Properties

api文档:

使用Properties读取配置文件信息



以上是关于Java集合框架 Map接口实现类--HashMap源码分析 & HasmMap与HashSet的关系 & HashTable & Properties(HashTable 的的主要内容,如果未能解决你的问题,请参考以下文章

java的集合类(MapList与Set比较)

Map接口框架图

java集合框架综述

Java集合框架详解

Java知识33 集合框架 List接口 Map 和set多测师

简单比较HashMap和TreeMap