Java HashMap 分析四篇连载
HashMap实际上是一个数组,数组里面的每个元素都是一个链表。每个元素在通过put方法放入HashMap中的时候,要按照如下步骤进行:
1.根据该元素自身提供的hashcode计算出散列值,该散列值就是数组的下标。
2.将新元素放入该数组位置的链表中。
先来看一下数组的定义:
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;
这是一个数组,transient关键字告诉我们它不会参与序列化。既然是一个数组,总有数目上限,也就意味着如果存入HashMap的元素太多,导致数组大小不能够存放所有的链表的时候,数组大小必须要能够调整。所以首先来考察一下数组容量的相关算法。
第一,Entry是什么类型?
static class Entry implements Map.Entry {
final K key;
V value;
Entry next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry n) {
value = v;
next = n;
key = k;
hash = h;
}
....
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public final int hashCode() {
return (key==null ? 0 : key.hashCode()) ^
(value==null ? 0 : value.hashCode());
}
....
这是一个HashMap类的内部静态类。实现了Map.Entry接口。接受两个模板参数K和V。key和hash一旦在构造函数中被初始化,就不可改变,并且由于有next的存在,Entry可以构成一个单向链表。
比较重要的是equals和hashCode方法。代码先列出来,后面再解释。
第二,初始容量的设定
大多数都在下面的构造函数里面.用于指定的initialCapacity不准小于0,也不能超过最大值。并且最终的capicity必须是2的n次方。还有如果使用了无参数的构造函数,默认会创建一个拥有16个元素的数组。
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);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
table = new Entry[capacity];
init();
}
第三,什么时候应该调整数组的大小?
算法是这样,有一个变量size保存了实际数组已经使用了多少个元素,并且如果size的值达到了变量threshold的值,就必须扩充数组的容量。threshold=capicity*loadFactor.capicity是数组最大的容纳元素个数,loadFactor可以在构造函数中制定,否则采用默认值0.75f。capicity的最大值是1<<30(也就是2的30次方,1073741824).由此我们可以看到HashMap最多存放10亿多个链表。
第四,如何调整数组大小?
答案是2倍,很像C++里面的vector的分配策略。
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry e = table[bucketIndex];
table[bucketIndex] = new Entry(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
Java HashMap 分析四篇连载的更多相关文章
- 【JAVA并发第四篇】线程安全
1.线程安全 多个线程对同一个共享变量进行读写操作时可能产生不可预见的结果,这就是线程安全问题. 线程安全的核心点就是共享变量,只有在共享变量的情况下才会有线程安全问题.这里说的共享变量,是指多个线程 ...
- Java学习第四篇:数组,排序,查找
一.数组 1.一维数组 (1).数组的定义 数据类型 数组名[]=new 数据类型[大小] public class Demo1 { public static void main(String[] ...
- Java系列--第四篇 基于Maven的SSME之发送邮件
在系列第一篇中,使用的是mybatis得到了一个小小的项目,而该项目的用户对象是有邮件地址的,如果按照邮件地址给对方去一封邮件会不会更能体现针对性呢,所以,我在这篇准备加入发送邮件的功能,利用的就是s ...
- 从.Net到Java学习第四篇——spring boot+redis
从.Net到Java学习系列目录 “学习java已经十天,有时也怀念当初.net的经典,让这语言将你我相连,怀念你......”接上一篇,本篇使用到的框架redis.FastJSON. 环境准备 安装 ...
- Java【第四篇】基本语法之--循环
循环语句功能 在循环条件满足的情况下,反复执行特定代码 循环语句的四个组成部分 初始化部分(init_statement)循环条件部分(test_exp) 循环体部分(body_statement) ...
- java核心技术第四篇之JDBC第二篇
01.JDBC连接池_连接池的概念: 1).什么是连接池:对于多用户程序,为每个用户单独创建一个Connection,会使程序降低效率.这时我们可以创建一个"容器", 这个容器中, ...
- Java 学习 第四篇;面向对象(1)
1:关于继承为了保证父类的良好封装性,不会被子类随意改变,设计父类时通常隐藏父类的内部数据,把父类属性改为private如果父类中可以被重写,但不希望被其他类自由访问可用protected修饰;2:什 ...
- 学习java随笔第四篇:运算符
算术运算符 "+":加法运算符,也可做字符连接用途 "-":减法运算符 "*":乘法运算符 "/":除法运算符 &quo ...
- java基础第四篇之面向对象
7.封装与面向对象 a.方法: public static void main(String[] args) { } 一般定义标准: 形参:一般把 不确定的量或者变化的量定义在形参位置//圆的的半径, ...
随机推荐
- Ubantu里面的Sublime Text3不支持中文的解决办法
参考的大佬链接:https://github.com/lyfeyaj/sublime-text-imfix 更新然后将系统升级到最新版本,在linux终端输入 sudo apt-get update ...
- <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible' />
代码一:<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> http-eq ...
- C语言复习---选择法排序
选择排序也是一种简单直观的排序算法 它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列:然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾. ...
- telegraf、influxDB、Grafana的安装与基本使用
目的理解influxDB的数据收集原理和方法为使用grafana分析数据及展示结作好准备介绍[收集数据] Telegraf 是一个用 Go 编写的代理程序,可收集系统和服务的统计数据,并写入到 Inf ...
- JavaScript 获取 flash 对象
关于js获取flash对象,网上有非常多的例子,我也尝试了不少方法. 虽然都能用,但是没有我最想要的东西, 后来看了下百度的,虽然很规范,各种情况都考虑到了,但是代码量却不是不容乐观, 前前后后将近2 ...
- 通过vnc访问无显卡服务器的图形环境
最近在一台没有显卡的 Power 服务器上,安装了Fedora 22,因为没有显卡,所以不能在本机启动Xserver,于是想通过vnc的方式远程访问服务器的图形环境. 在服务器上安装好xserver和 ...
- 关于升级程序版本时version与build修改的问题
CHENYILONG Blog 关于升级程序版本时version与build修改的问题 #问题#从V1.0升级到V1.0.1.version是一定要改的,那么build需要修改吗? #解答#一般习惯上 ...
- Floyd判圈算法 UVA 11549 - Calculator Conundrum
题意:给定一个数k,每次计算k的平方,然后截取最高的n位,然后不断重复这两个步骤,问这样可以得到的最大的数是多少? Floyd判圈算法:这个算法用在循环问题中,例如这个题目中,在不断重复中,一定有一个 ...
- 《区块链100问》第13集:比特币和Q币有哪些不同?
比特币是一种去中心化的数字资产,没有发行主体.Q币是由腾讯公司发行的电子货币,类似于电子积分,其实不是货币. Q币需要有中心化的发行机构,Q币因为腾讯公司的信用背书,才能被认可和使用.使用范围也局限在 ...
- springboot整合rabbitmq客户端连接报超时异常问题解决:An unexpected connection driver error occured java.net.SocketException: Socket Closed,java.util.concurrent.TimeoutException
我用的是springboot2.0.6版本,对应的ampq也是2.0.6版本,然后启动一直报: 还有java.util.concurrent.TimeoutException, 用户授权什么的都对,很 ...