java容器

java中的容器

一、HashMap源码理解

HashMap底层采用数组链表的方式实现。jdk1.7之前以k-v键值对方式封装在Map的内部接口Entry对象,1.8 封装在Entry实现类Node对象中,jdk1.7数组就是Entry[],1.8就是Node[]中。数据结构:索引key、值value、指向下一个对象的指针next。

new一个HashMap默认容量未1<<4 = 16.最大容量为2的30次方。

为什么HashMap的最大容量为1<<30?(左移)

因为hashMap基于性能考虑,采用Int所表示的最大范围 static final int MAXIMUM_CAPACITY = 1 << 30;。

一个int是4个字节,32个二进制位,按理可以左移31位,但是左边最高位是符号位,需要用来表示正负,所以只能移动30位,故最大容量为2的30次方。

  1. 为什么为16,2的指数幂。

因为16是2的指数幂,二进制表示为1111,get(key)定位在HashMap的Entry数组中位置通过key的hash值&数组长度-1.(任何数&1111还等于本身,可以在理论上使数组均匀公平分配)

  1. put(key,value)

当key为null,则将value放到Eytry[0]中;

当key不为null,则获取key的哈希值快速定位在数组中的位置,若该位置上已存在其他元素,那么这个元素则以链表的形式存放。在进行遍历比较key相同则覆盖其value,返回旧的value。

当map中不存在当前添加的key则添加一个新的Entry对象。jdk1.7之前采用头插法添加到链表中,jdk1.8采用了尾插法。头插法在多线程扩容时会更改链表的顺序,导致链表成环。尾插法则不改变链表的顺序,不会造成链表成环。

二、HashSet源码理解

HashSet底层调用HashMap实现,为了满足保存唯一的值,将数据保存在key中,value都统一采用一个空Object对象填充。

HashSet中保存对象,一定要重写其hashcode和equals方法。因为key要保持唯一,set中对象保持唯一,需要通过hashcode和equals方法确定。

三、HashTable源码理解

HashTable底层实现也是数组链表数据结构,和hashMap一致。

二者不同的地方

  1. HashTable的初始容量为11,是一个质数,原因是二者获取数组中下标的方式不同,HashTable采用(key的hash值&0x7FFFFFF) % 数组长度。
  2. 对HashTable操作的方法(put、get、remove等)都是加锁同步的安全容器,hashMap则不加锁,是非安全容器。
  3. HashTable的key和value都不允许为null。
  4. 扩容方式不同:hashTable扩容采用左移一位+1;hashMap是左移一位。

四、LinkedHashMap源码理解

底层调用的来时HashMap,通过继承HashMap,自己又定义了指向链表头和尾的数据结构并继承HashMap中的Node数据节后,添加了header和tail节点,实现的是一个双向链表。

**排序方式:**可以是按照插入顺序和访问顺序进行排序。默认采用的是插入顺序。

访问顺序进行的排序:是根据LRU(最近最少使用的移除)方式实现,其思想是每次将最新访问连接到header元素。。这种映射很适合构建 LRU 缓存。LinkedHashMap 提供了 removeEldestEntry(Map.Entry<K,V> eldest) 方法。该方法可提供在每次添加新条目时移除最旧条目的实现程序。

五、LinkedHashSet源码理解

底层继承了HashSet,HashSet中对其实现是调用的LinkedhashMap。

六、ArrayList源码理解

ArrayList底层采用Object[]存放对象,故ArrayList的泛型必须是对象类型。其添加数据对象时,可以指定索引位置,不指定则会以队列的方式加入到数组的尾部。其默认大小未10,在第一次添加对象时分配内存。最大内存未2的31次方。

添加的过程中会先判断当前数组容量是否还够,(ArraList的扩容银子时1)不够则进行grow方法进行扩容,扩容原来的1.5倍(右移一位)。

七、LinkedList源码理解

LinkedList是基于链表实现的,采用双向链表,具有一个头指针和尾指针,每一个Node节点都有指向上一个和下一个节点的属性。

八、ConcurrentHashMap源码理解

ConcurrentHashMap是线程安全的容器,其实现原理基于Java的内存模型。对可访问的线程数有限制。jdk1.8之前的采用分段式锁技术实现。

jdk1.8之前ConcurrentHashMap存储结构:

  1. ConcurrentHashMap中用final修饰的segment数组来存放数据。

  2. egment对象则继承了ReenTrantLock使得Segment充当锁的角色。Segment对象中的HashEntry数组是真正存放数据地方。

  3. HashEntry是个Static final类,其数据结构和HashMap中的Node数据结构一致,只是在value和指向下一个节点的next用volatile修饰,达到并发效果。

存储结构总结:

相比于HashTable和用同步包装器包装的HashMap,ConcurrentHashMap是将加锁的范围所有到整个数组的一部分。ConcurrentHashMap的分段式索技术采用二级数组方式,第一级数组是用来分段,第二级数组(Segment对象中存放的HashEntry数组)和HashMap底层实现一致,采用数组链表的实现方式,但是ConcurrentHashMap的第二级数组HashEtry不同于HashMap的是在在value和指向下一个节点的next用volatile修饰。

实现多线程并发总结:

  1. 使用分段式锁实现多个线程间数据更深层次的共享访问。减少同一锁定的访问频率和持有锁的时间。
  2. 底层采用HashEntry的不变性来降低线程读操作使对锁的要求(类似于String一样,采用final修饰)。
  3. 通过Volatile变量实现不同线程间读/写操作的内存可见性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值