JAVA源码走读(一) HashMap与ArrayList
HashMap
一、HashMap基本概念:
HashMap是基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
HashMap不是线程安全的,如果想要线程安全的HashMap,可以通过Collections类的静态方法synchronizedMap获得线程安全的HashMap。
Map map = Connections.synchronized(new HashMap());
二、HashMap的数据结构
HashMap的底层主要是基于数组和链表来实现的,它之所以又相当快的查询速度是因为它是通过计算散列码来决定存储的位置。
在构造HashMap的时候如果我们指定了加载因子和初始容量的话就调用第一个构造方法,否则的话就是用默认的。默认初始容量为16,默认加载因子为0.75。
三、HashMap的存储结构
public V put(K key, V value) {
// 若“key为null”,则将该键值对添加到table[0]中。
if (key == null)
return putForNullKey(value);
// 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。
int hash = hash(key.hashCode());
//搜索指定hash值在对应table中的索引
int i = indexFor(hash, table.length);
// 循环遍历Entry数组,若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出!
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //如果key相同则覆盖并返回旧值
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//修改次数+1
modCount++;
//将key-value添加到table[i]处
addEntry(hash, key, value, i);
return null;
}
我们一般对哈希表的散列很自然地会想到用hash值对length取模(即除法散列法),Hashtable中也是这样实现的,这种方法基本能保证元素在哈希表中散列的比较均匀,但取模会用到除法运算,效率很低,HashMap中则通过h&(length-1)的方法来代替取模,同样实现了均匀的散列,但效率要高很多,这也是HashMap对Hashtable的一个改进。
ArrayList
一、首先是ArrayList的继承体系:
public class ArrayList<E> extends AbstractList<E> implements List<E>,RandomAccess,Cloneable,java.io.Serializable
public class ArrayList<E> extends AbstractList<E> implements List<E>,RandomAccess,Cloneable,java.io.Serializable
二、增加一条数据,因为数组长度一旦定义则不能够变化,所以使用了ensureCapacity方法来确保数组能动态变化,通过Arrays.copyOf拷贝到新的数组 容量size+1方法源码:
public void ensureCapacity(int minCapacity){
modCount++;
int oldCapacity = elementData.length; //得到目前数组的容量大小
if(minCapacity > oldCapacity){ //如果目前数组容量小于传入的参数minCapacity
Object oldData[] = elementData;
Int newCapacity = (oldCapacity *3) /2 + 1 则新生成一个容量
If(newCapacity < minCapacity) //如果新生成的容量依旧小于传入的残水
NewCapacity = minCapacity; //将参数赋予这个新容量
elementData = Arrays.copyOf(elementData,newCapacity);//将数组扩大到newCapacity的长度。
}
}
}
三、contains方法用来判断ArrayList中对象o是否在,调用了indexOf来实现
public int indexOf(Object o){
if(null == 0){ //如果o为null
for(int I = 0;i < size;i++){ //循环遍历ArrayList底层的数组
if(elementData[i] == null){
return i;
}else {
for(int i = 0;I < size;i++){
if(o.equals(elementData[i])){ //若发现其中某个元素等于o,则返回该元素的索引
return i;
}
}
四、删除一个元素且不说最好一个元素则需要移动底层数组,这个会导致效率低下,故ArrayList不适合删除操作过多的场景.
public E remove(int index){
RangeCheck(index); //检查索引边界
modCount++;
E oldValue = (E)elemetData[index]; //得到index上的元素
Int numMoved = size – index -1; //得到需要移动的元素熟练,注意这里要减1,因为不包括要删除的元素 If(numMoved > 0) //需要移动的元素数量大于0,则开始移动ArrayList底层数组 System.arraycopy(elementData,index+1,elementData,index,numMoved);
elementData[--size] = null;
return oldValue;
}
JAVA源码走读(一) HashMap与ArrayList的更多相关文章
- Java源码系列2——HashMap
HashMap 的源码很多也很复杂,本文只是摘取简单常用的部分代码进行分析.能力有限,欢迎指正. HASH 值的计算 前置知识--位运算 按位异或操作符^:1^1=0, 0^0=0, 1^0=0, 值 ...
- 【java集合框架源码剖析系列】java源码剖析之HashMap
前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...
- Java源码解读(一)——HashMap
HashMap作为常用的一种数据结构,阅读源码去了解其底层的实现是十分有必要的.在这里也分享自己阅读源码遇到的困难以及自己的思考. HashMap的源码介绍已经有许许多多的博客,这里只记录了一些我看源 ...
- Java 源码刨析 - HashMap 底层实现原理是什么?JDK8 做了哪些优化?
[基本结构] 在 JDK 1.7 中 HashMap 是以数组加链表的形式组成的: JDK 1.8 之后新增了红黑树的组成结构,当链表大于 8 并且容量大于 64 时,链表结构会转换成红黑树结构,它的 ...
- java源码学习(四)ArrayList
ArrayList ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下, ...
- JAVA源码走读(二)二分查找与Arrays类
给数组赋值:通过fill方法. 对数组排序:通过sort方法,按升序.比较数组:通过equals方法比较数组中元素值是否相等.查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找 ...
- [java源码解析]对HashMap源码的分析(二)
上文我们讲了HashMap那骚骚的逻辑结构,这一篇我们来吹吹它的实现思想,也就是算法层面.有兴趣看下或者回顾上一篇HashMap逻辑层面的,可以看下HashMap源码解析(一).使用了哈希表得“拉链法 ...
- [java源码解析]对HashMap源码的分析(一)
最近有空的时候研究了下HashMap的源码,平时我用HashMap主要拿来当业务数据整理后的容器,一直觉得它比较灵活和好用, 这样 的便利性跟它的组成结构有很大的关系. 直接开门见山,先简要说明一下H ...
- Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?
我们知道 HashMap 的底层是由数组,链表,红黑树组成的,在 HashMap 做扩容操作时,除了把数组容量扩大为原来的两倍外,还会对所有元素重新计算 hash 值,因为长度扩大以后,hash值也随 ...
随机推荐
- 采用OLEDB数据库方式向指定的Excel添加数据,怪像!
我们都知道,对Excel进行操作,其实方法是多种多样的,例如采用Office.Interop;例如采用ASPCell:例如采用NPOI:再例如采用数据库连接的方式OLEDB,etc. 还是先说说背景吧 ...
- 10道javascript笔试题
1.考察this JavaScript var length = 10; function fn() { console.log(this.length); } var obj = { length: ...
- Android studio快捷键大全 和 eclipse对照(原)
Ctrl+空格 代码提示 (同Eclipse中Alt+/) Ctrl+Shjft+N 项目 ...
- MySql数据库忘记root密码
以windows为例: 1. 关闭正在运行的MySQL服务.(services.msc运行停止服务) 2. 打开DOS窗口,转到mysql\bin目录.(输入cd..返回到c盘根目录下,一般MySQL ...
- 联合(union)类型有哪些使用场景
2013-08-22 - 18:17:50 by Gold_Lion 今天突然碰到“联合”这个数据类型了,平时用的不多,实在也想不出来它到底能帮我干嘛?于是google了一下,终于有一个是利用联合( ...
- 鼠标焦点变化引起mouseout事件
做了个小手术,渐渐回归网络啦! 问题: 在自制的提示离鼠标太近时,会引起无法提示的功能. 自制提示离图片太近时,提示图片一直一闪一闪的,截图截不出来,就只放改善后的图片(不闪). 原因: 为什么呢?书 ...
- 电脑用miniDP链接显示器后电脑没声音
今天用笔记本T440s miniDP 链接戴尔U2515显示器的 DP 连接后发现笔记本没声音了 原因: miniDP 不仅能支持视频传输还支持音频, 所以声音就改为从显示器发出了 但是我想让电脑输出 ...
- C++继承,多重继承,虚继承的构造函数以及析构函数的调用顺序问题
#include <iostream> using namespace std; class A{ int data_a; public: A(){ data_a = ; cout < ...
- jquery怎么获取radio选中的值
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- VS大视野
vs的本质:他是微软公司的员工一起开发的一个项目: 既然是项目:那么就是用编程语言编出来的! 用的是C# C#有他的特点:继承,封装,多态!等 我们在使用vs的时候,为什么可以使用很多的里面已经存在的 ...