hashmap和hashtable数组扩容_散列表扩容

hashmap和hashtable数组扩容_散列表扩容前言众所周知,hashmap和Arraylist作为java中非常重要的一种数据结构,应用场景非常广泛,这篇文章主要针对HashMap和ArrayList的扩容机制进行分析。HashMap扩容机制分析在说HashMap扩容机制之前,有必要简述下HashMap的基本结构。以便各位更加清除的理解HashMap的底层是如何扩容的。HashMap自JDK1.8之后结构采用数组+单链表【单链表长度达到…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言

众所周知,hashmap和Arraylist作为java中非常重要的一种数据结构,应用场景非常广泛,这篇文章主要针对HashMap和ArrayList的扩容机制进行分析。

HashMap扩容机制分析

在说HashMap扩容机制之前,有必要简述下HashMap的基本结构。以便各位更加清除的理解HashMap的底层是如何扩容的。HashMap自JDK1.8之后结构采用数组+单链表【单链表长度达到8后结构转化为红黑树】。所以从结构上进行分析,HashMap的最基本结构只有两种。要么是数组元素+单链表,要么是数组元素+红黑树.当然一个HashMap可以有这两个结构同时存在。下面就着重叙述HashMap底层的扩容了。
了解HashMap的读者都知道HashMap的初始化大小是16,至于为什么是16,可以参看我之前的博客
这里不在叙述。
HashMap如何扩容呢?下面来看看HashMap 底层扩容源码!

 final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)  	// 这个是HashMap对象的阈值,默认是0.75*16.只要put操作进行的时候,一旦HashMap存放的数据的大小超过阈值,就一定会扩容。
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

下面接着来看下JDK1.8扩容方法的源码!
在这里扩容不是直接原来的结构上进行顺序性的增加,而是先计算扩容之后的容量。然后重新建一个容量大小数组,在将原数组的元素按照指定的方式加入到新的数组当中去!

 final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            else if (( newCap = oldCap << 1 ) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)  // 这里就是扩容的具体实现。 newCap = oldCap << 1 ,这个步骤对原来的容量扩大一倍!并且如果原来容量不小于16*0.75,则会对新HashMap阈值也扩大一倍!
                newThr = oldThr << 1; // double threshold
        }
        else if (oldThr > 0) // initial capacity was placed in threshold
            newCap = oldThr;
        else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        if (oldTab != null) {
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;   // 用于存放对象的节点
                if ((e = oldTab[j]) != null) {  // 获取hashMap的第j个存储位置的节点对象,如果不为空,则清空处理。
                    oldTab[j] = null;
                    if (e.next == null)   // 如果该节点的下一个节点为空。说明该链表长度为1.
                        newTab[e.hash & (newCap - 1)] = e;    // 将这个节点放入e.hash()&(newCap-1)的存储位置上。
                    else if (e instanceof TreeNode)   //如果该节点是树形节点对象。
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); 
                    else { // 这里就是链表结构。
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                        //为什么使用do while 因为前面已经进行了多次判断,到这里链表的长度一定是大于1的。因此一定可以获取下一个节点。
                        do {
                            next = e.next;  //获取下一个节点并存放至 next中
                            if ((e.hash & oldCap) == 0) {  //原来的hash值新增的那个bit还是0,是0的话存储的索引不变
                                if (loTail == null)  // 初始化
                                    loHead = e;   //将该节点设为头结点。
                                else
                                    loTail.next = e;
                                loTail = e; //将当前节点设为尾节点用于下一次链表链接。
                            }
                            else {   //原来的hash值新增的那个bit不为0,存储的索引位置为 j+OldCap
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);   //遍历循环值最后一个节点
                        if (loTail != null) {   // 如果临时节点数据还在,清空临时节点
                            loTail.next = null;
                            newTab[j] = loHead;  // 将这个节点放入新数组的第j个存储位置上。
                        }
                        if (hiTail != null) {// 如果临时节点数据还在,清空临时节点
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead; // 将这个节点放在新数组的第j+oldCap的存储位置上。
                        }
                    }
                }
            }
        }
        return newTab;
    }

附上测试代码:

package DataStruct;

import java.util.HashMap;
import java.util.Map;

public class HashMapResize {
	
	/**
	 *  this is A class for the HashMapResize test
	 */

	static void Resize() {
		
		Map<String, String> hashMap = new HashMap<String, String>();
		
		for(int i=0;i<20;i++) {
			
			hashMap.put(String.valueOf(i),"AAA");
		}
		
	}
	public static void main(String[] args) {	
		Resize();
	}

}

看图:运行四次之后的结果:
在这里插入图片描述清晰的看见,这里面的容量就是16.
继续运行size=12.查看结果:

在这里插入图片描述
容量还是为16。在运行一次查看结果:
在这里插入图片描述可以看到容量就变为32了.阈值也翻倍了。

ArrayList扩容机制

和这个差不过。扩容的大体思想都是一样的,但是比HashMap简单的多。不过是ArrayList的初始容量为10.
还有扩容的之后的容量是NewLength=OldLength+OldLength>>1;
附上相关源码:

  private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

这个源码相对简单!读者可以自己看懂!
就写这么多了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/193307.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 单隐层前馈神经网络网络构造_前馈型神经网络常用于

    单隐层前馈神经网络网络构造_前馈型神经网络常用于这篇博客主要介绍神经网络基础,单隐层前馈神经网络与反向传播算法。神经网络故名思议是由人的神经系统启发而得来的一种模型。神经网络可以用来做分类和回归等任务,其具有很好的非线性拟合能力。接下来我们就来详细介绍一下但隐层前馈神经网络。首先我们来看一下神经元的数学模型,如下图所示:可以看到为输入信号,而神经元最终输出为,由此我们可以看到,单个神经元是多输入单输出的。但是从上图我们可以看到,…

    2025年6月19日
    0
  • dropdownlist控件的几个属性selectedIndex、selectedItem、selectedValue、selectedItem.Text、selectedItem.value的区别…

    dropdownlist控件的几个属性selectedIndex、selectedItem、selectedValue、selectedItem.Text、selectedItem.value的区别…1.selectedIndex——指的是dropdownlist中选项的索引,为int,从0开始,可读可写2.selectedItem——指的是选中的dropdownlist中选项,为ListItem,只读不写3.selectedValue——指的是选中的dropdownlist中选项的值,为string,只读不写4.selectedItem.Text——指的是选中的drop…

    2022年10月16日
    0
  • 基于Java和MySQL的图书管理系统[通俗易懂]

    Java图书管理系统设计人:wangyunpeng_bio项目需求随着计算机的普及和应用水平的提高,经过考察比较,决定利用自己的Java知识开发小型的图书管理系统,方便图书的管理。图书管理系统是典型的信息管理系统。本次作业利用JAVA开发工具Eclipse和MySQL数据库来开发这个图书管理系统。该系统要解决的图书管理所要解决的问题,可以满足图书管理基本要求,包括添加、管理等功能。…

    2022年4月12日
    117
  • 五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程

    五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程在windows安装Android的开发环境不简单也说不上算复杂,本文写给第一次想在自己Windows上建立Android开发环境投入Android浪潮的朋友们,为了确保大家能顺利完成开发环境的搭建,文章写的尽量详细,希望对准备进入Android开发的朋友有帮助。本教程将分为五个步骤来完成Android开发环境的部署。第一步:安装JDK。第二步:配置Windows上JDK的变量环…

    2022年7月23日
    8
  • 小旋风asp服务器出错_小旋风服务器用来干什么的

    小旋风asp服务器出错_小旋风服务器用来干什么的 点击是出现下列的对话框:可能是因为因为开着迅雷,因为迅雷是用的80号端口,可以关了迅雷试试,

    2022年10月24日
    0
  • 161套javaWeb项目源码免费分享[通俗易懂]

    161套javaWeb项目源码免费分享[通俗易懂]最近很多学生在找关于java开发的学生管理系统,学生选课系统,车辆管理系统,商城系统,项目申报系统,教务管理系统,班级管理系统,博客系统。。。。。。。。我找了一些前几年的项目,感觉还行,虽然项目但技术都是一样的,可以用来做课程设计和毕业设计项目参考,但不要完全照搬哦就不再展示了,需要的可以收藏本篇文章,最好可以四连,关注点赞收藏订阅,下载不迷路链接:https://pan.baidu.com/s/1JX3u5v1alDcMpbG8s134AA提取码:wimo…

    2022年7月9日
    82

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号