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的更多相关文章

  1. Java源码系列2——HashMap

    HashMap 的源码很多也很复杂,本文只是摘取简单常用的部分代码进行分析.能力有限,欢迎指正. HASH 值的计算 前置知识--位运算 按位异或操作符^:1^1=0, 0^0=0, 1^0=0, 值 ...

  2. 【java集合框架源码剖析系列】java源码剖析之HashMap

    前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...

  3. Java源码解读(一)——HashMap

    HashMap作为常用的一种数据结构,阅读源码去了解其底层的实现是十分有必要的.在这里也分享自己阅读源码遇到的困难以及自己的思考. HashMap的源码介绍已经有许许多多的博客,这里只记录了一些我看源 ...

  4. Java 源码刨析 - HashMap 底层实现原理是什么?JDK8 做了哪些优化?

    [基本结构] 在 JDK 1.7 中 HashMap 是以数组加链表的形式组成的: JDK 1.8 之后新增了红黑树的组成结构,当链表大于 8 并且容量大于 64 时,链表结构会转换成红黑树结构,它的 ...

  5. java源码学习(四)ArrayList

    ArrayList ​ ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ​ ArrayList不是线程安全的,只能用在单线程环境下, ...

  6. JAVA源码走读(二)二分查找与Arrays类

    给数组赋值:通过fill方法. 对数组排序:通过sort方法,按升序.比较数组:通过equals方法比较数组中元素值是否相等.查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找 ...

  7. [java源码解析]对HashMap源码的分析(二)

    上文我们讲了HashMap那骚骚的逻辑结构,这一篇我们来吹吹它的实现思想,也就是算法层面.有兴趣看下或者回顾上一篇HashMap逻辑层面的,可以看下HashMap源码解析(一).使用了哈希表得“拉链法 ...

  8. [java源码解析]对HashMap源码的分析(一)

    最近有空的时候研究了下HashMap的源码,平时我用HashMap主要拿来当业务数据整理后的容器,一直觉得它比较灵活和好用, 这样 的便利性跟它的组成结构有很大的关系. 直接开门见山,先简要说明一下H ...

  9. Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?

    我们知道 HashMap 的底层是由数组,链表,红黑树组成的,在 HashMap 做扩容操作时,除了把数组容量扩大为原来的两倍外,还会对所有元素重新计算 hash 值,因为长度扩大以后,hash值也随 ...

随机推荐

  1. Block对象

    背景:回调机制中回调设置代码和回调方法的具体实现无法写在同一段代码中.Mac OS X 10.6和iOS4种引入了Block对象.Block对象看上去是一段代码,但是可以当作数据来传递. 定义Bloc ...

  2. XML代码生成器——XMLFACTORY 简介(二)

    XML代码生成器——XMLFACTORY 简介(二)      因为春节和项目上线的原因,离写上一篇文章的时间已经好久了. 不知道是事情太多了,还是自已效率太低了.总之是时间不够用. 哎,苦逼的程序员 ...

  3. libc++

    今天测试最新的微信iOS SDK, 仅仅是建了一个空的工程,把sdk加进去运行,就报了以下错误: Undefined symbols for architecture x86_64: "op ...

  4. Android 中onSaveInstanceState和onRestoreInstanceState学习

    1. 基本作用: Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate().onPaus ...

  5. python、matlab、c++的括号增加次序,以及图片存储方式

    1 增加次序: python:(同c++多维数组) np.zeros([2,3,4]),先是按照内存空间均分为2份,每份又均分3份,最终再细分4份            2最大份,先按左分 例子:re ...

  6. Android倒计时:计算两个时间将得到的时间差转化为倒计时(xx时xx分xx秒格式)

    首先是一个自定义控件: public class RushBuyCountDownTimerView extends LinearLayout { // 小时,十位 private TextView ...

  7. 跨服务器的session共享

    四种 一.NFS(Net FileSystem): sun公司提供的,并发处理的效率不高,但操作方便 二.基于数据库的session共享 三.基于cookie的session共享 原理:将sessio ...

  8. Eclipse “cannot be resolved to a type” 错误

    eclipse中遇到了“XX cannot be resolved to a type”的报错信息.网上找了些资料,本文将做以简单总结.     (1)jdk不匹配(或不存在) 项目指定的jdk为“j ...

  9. 《C标准库》——之<string.h>

    <string.h>里的字符串操作函数是经常要用到的,因此阅读了源码后自己实现了一些: 拷贝函数 void * Mymemcpy(void * sDst, const void * sSr ...

  10. JS this指向问题

    <button onclick=(function(){alert(this)})()>I'm button</button>//this指代window <button ...