为什么要指定HashMap的容量?

首先创建HashMap时,指定容量比如1024后,并不是HashMap的size不是1024,而是0,插入多少元素,size就是多少;

然后如果不指定HashMap的容量,要插入768个元素,第一次容量为16,需要持续扩容多次到1024,才能保存1024*0.75=768个元素;

所以你如果想插入个元素,你得需要指定容量,2048*0.75=1536>1000;

而HashMap扩容是非常非常消耗性能的,Java7中每次先创建2倍当前容量的新数组,然后再将老数组中的所有元素再次通过hash&(length-1)的方式散列到HashMap中;

Java8中HashMap虽然不需要重新根据hash值散列后的新数组下标,但是由于需要遍历每个Node数组的链表或红黑树中的每个元素,根据元素key的hash值与原来老数组的容量的关系来决定放到新Node数组哪一半(2倍扩容),还是需要时间的;

具体Java8 HashMap resize源码怎么扩容以及如何避免Java7 HashMap死循环的可简单参考:JAVA7与JAVA8中的HASHMAP和CONCURRENTHASHMAP知识点总结

HashMap指定容量初始化后,底层Hash数组已经被分配内存了吗?

Java8 HashMap指定容量构造方法源码,会调整threshold为2的整数次幂,比如指定容量为1000,则threshold为1024:

public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
 /**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

可以根据源码看到,在指定的HashMap初始容量后,底层的Hash数组Node<K,V>[] table此时并没有被初始化,依旧为null;

那么是什么时候被初始化的呢?答案是第一次put元素的时候。

put源码如下:

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
......
......
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)
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;
......
......

上面代码的加红字体,首先第一次调用put方法插入key-value,会调用resize方法,由于指定了HashMap的容量,那么这里会将底层的Hash数组Node<K,V>[] table初始化容量为上面所说的2的整数次幂;

resize源码,Java7 HashMap是根据元素Hash值重新散列,Java8 HashMap却不一样,这里put、resize方法源码只截取了第一次指定容量扩容相关的源码,详细的内容可简单参考:JAVA7与JAVA8中的HASHMAP和CONCURRENTHASHMAP知识点总结

为什么要指定HashMap的容量?HashMap指定容量初始化后,底层Hash数组已经被分配内存了吗?的更多相关文章

  1. RestTemplate接收HashMap变为LinkedHashMap,RestTemplate接收数据后转成json数据出现反斜杠

    使用postForObject方法远程调用接口,正常会返回List<HashMap>,然而实际上却返回List<LinkedHashMap>,同时将此数据进行json转换,变成 ...

  2. CentOS7之按时间段截取指定的Tomcat日志到指定文件的方法

    CentOS7之按时间段截取指定的Tomcat日志到指定文件的方法 sed -n '/2016-11-02 15:00:/,/2016-11-02 15:05:/p' catalina.out > ...

  3. [转]C#中调用资源管理器(Explorer.exe)打开指定文件夹 + 并选中指定文件 + 调用(系统默认的播放类)软件(如WMP)打开(播放歌曲等)文件

    原文:http://www.crifan.com/csharp_call_explorer_to_open_destinate_folder_and_select_specific_file/ C#中 ...

  4. 通过ASP禁止指定IP和只允许指定IP访问网站的代码

    过ASP禁止指定IP和只允许指定IP访问网站的代码,需要的朋友可以参考下. 一.禁止指定IP防问网站,并执行相应操作: 代码如下: <% Dim IP,IPString,VisitIP '设置I ...

  5. Java基础知识强化之集合框架笔记57:Map集合之HashMap集合(HashMap<Student,String>)的案例

    1. HashMap集合(HashMap<Student,String>)的案例 HashMap<Student,String>键:Student      要求:如果两个对象 ...

  6. Java基础知识强化之集合框架笔记56:Map集合之HashMap集合(HashMap<String,Student>)的案例

    1. HashMap集合(HashMap<String,Student>)的案例 HashMap是最常用的Map集合,它的键值对在存储时要根据键的哈希码来确定值放在哪里. HashMap的 ...

  7. Java基础知识强化之集合框架笔记54:Map集合之HashMap集合(HashMap<String,String>)的案例

    1. HashMap集合 HashMap集合(HashMap<String,String>)的案例 2. 代码示例: package cn.itcast_02; import java.u ...

  8. [置顶] LOAD语句:利用MSSQL中的xp_cmdshell功能,将指定文件夹下的指定文件,生成mysql的LOAD语句

    LOAD语句:利用MSSQL中的xp_cmdshell功能,将指定文件夹下的指定文件,生成mysql的LOAD语句 declare @sql varchar(4000), @dirpath varch ...

  9. 【java】HashMap、Map、Set、HashMap.put()、HashMap.keySet()、HashMap.entrySet()、Map.Entry内部类

    package com.tn.hashMap; public class Student { private String id; private String name; public Studen ...

随机推荐

  1. highcharts实现组织机构的点击选中和取消选中事件

    代码   Highcharts.chart('container', { chart: { height: 600, inverted: true }, title: { text: 'Highsof ...

  2. kibana We couldn't activate monitoring

    调节一下监控状态查询的时间范围,有时候,刚启动监控,数据没有生成.把”last 1 hour“改成 具体有数据的时间 用如下语句查看,监控日志在不断生成.重启kibana后正常有监控画面了. GET ...

  3. 本地项目git初始化并提交远程仓库

    1.先在远程仓库(如github)创建项目,为了避免错误,不要初始化 README, license, 或者gitignore文件 . 2.打开Terminal终端 3.切换到你的本地项目目录 4.初 ...

  4. ImageView基本用法

    1.background通常指的都是背景,而src指的是内容. 2.当使用src填入图片时,是按照图片大小直接填充,并不会进行拉伸. 3.scaleType缩放类型设置: fitXY:对图像的横向与纵 ...

  5. .Net Core2.2 在IIS发布

    .Net Core应用发布到IIS主要是如下的三个步骤: (1)在Windows Server上安装 .Net Core Hosting Bundle (2)在IIS管理器中创建IIS站点 (3)部署 ...

  6. List泛型用法(转载)

    网上的List泛型用法,未验证,目测基本正确,教学用资料. 1.  List的基础.常用方法: 声明: 1.List<T> mList = new List<T>(); T为列 ...

  7. delegate、Action、Func的用法

    委托的特点 委托类似于 C++ 函数指针,但它们是类型安全的. 委托允许将方法作为参数进行传递. 委托可用于定义回调方法. 委托可以链接在一起. delegate的用法 delegate void B ...

  8. C++:构造函数

    问题提出 默认初始化 答案 ▶问题提出 主要是在VC++ 2015里经常提示莫名其妙的编译错误. 分析一下,为什么Java里构造函数这个问题很简单: 1. C++里对象类型不止有按引用传递,还可能拷贝 ...

  9. 新版GRANAFA K8S插件 K8S NODE 图表不显示问题解决方法

    原文:https://www.wchao.site/archives/granafa-k8s 其他参考:https://blog.csdn.net/bbwangj/article/details/82 ...

  10. 8.Javascript-map、reduce、filter 等高阶函数

    高阶函数 高阶函数是对其他函数进行操作的函数,可以将它们作为参数或通过返回它们.简单来说,高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回. 例如Array.prototype.map,Ar ...