集合框架库02
1.ArrayDeque、Stack、LinkedList区别
(1)底层数据结构
ArrayDeque:
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
Stack:
public
class Stack<E> extends Vector<E>
LinkedList:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
ArrayDeque实现Deque接口,Stack继承于Vector,LinkedList实现Deque与List接口Stack与Arraydeque、LinkedList都可以作为栈使用
(2)方法
(3)线程安全
(4)使用
频繁的插入、删除操作:LinkedList
频繁的随机访问操作:ArrayDeque
未知的初始数据量:LinkedList
2.并发异常 ConcurrentModificationException
modCount 记录对于集合结构修改的次数, 构建迭代器时expectedModCount = modCount,修改集合结构modCount++,迭代器迭代下一元素,发现当前的modCount与期望值expectedModCount不符就会抛出 ConcurrentModificationException
fast-fail机制non-fast fail机制 CopyOnWriteArrayList 线程安全的ArrayList
加锁 + 底层操作都是基于数组的副本实现
3.HashSet,LinkedHashSet、TreeSet之间的区别
Hashset:key和value是一个占位符,当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相等
LinkedHashSet:LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
TreeSet:TreeSet类型是J2SE中唯一可实现自动排序的类型
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向 TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
4.HashMap底层结构(数据结构 + put + hash算法)
HashMap的底层是由数组+链表的形式,数据结构中又叫“链表散列”
HashMap:数组+链表+红黑树
(1)特点
1)快速存储 :比如当我们对hashmap进行get和put的时候速度非常快
2) 快速查找(时间复杂度o(1))当我们通过key去get一个value的时候时间复杂度非常的低,效率非常高
3) 可伸缩:1数组扩容,边长。2,单线列表如果长度超过8的话会变成红黑树
(2)Hash计算
Hash值=(hashcode)^(hashcode >>> 16)
Hashcode予hashcode自己向右位移16位的异或运算。这样可以确保算出来的值足够随机。因为进行hash计算的时候足够分散,以便于计算数组下标的时候算的值足够分散。前面说过hashmap的底层是由数组组成,数组默认大小是16,那么数组下标是怎么计算出来的呢,那就是:
数组下标:hash&(16-1) = hash%16
对哈市计算得到的hash进行16的求余,得到一个16的位数,比如说是1到15之间的一个数,hashmap会与hash值和15进行予运算。这样可以效率会更高。计算机中会容易识别这种向右位移,向左位移。
(3)put方法
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);//threshold 阈值
}
if (key == null)
return putForNullKey(value);
int hash = hash(key); //扰动处理后的key的hashcode
int i = indexFor(hash, table.length);//值应该存放在哪个下标下面
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k; //key 小明 value 13 key 小明 value 12
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //当有重复的key插入的时候就会替换掉之前的
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
5.HashMap和HashTable的区别和联系?
(1)联系
a.都实现了Map接口,保存了Key-Value(键值对)
b.两者的数据结构类似。HashMap和HashTable都是由数组元素为链表头节点的数组组成。
(2)区别
a.继承的父类不同:HashMap继承AbstractMap;HashTable继承Dictionary类
b.HashMap是线程不安全的,而HashTable是线程安全的;
c.HashMap没有contians,只有containsKey和containsValue,认为contians会容易引起误解;
HashTable保留了contains,containsValue和containsKey方法。(但contains和containsValue的功能是相同的)
d.HashTable中key和value都不允许为null;
HashMap中空值可以作为Key,也可以有一个/多个Key的值为空值;
e.扩容方式不同:
HashMap的hash数组默认长度大小为16,扩容方式为2的指数:
HashTable的hash数组默认长度大小为11,扩容方式为两倍加一:
6.Java中的四种引用
- 强引用 A a = new A(); a是强引用,gc永远不会被引用的对象
- 软引用 SoftReference 系统将要发生内存溢出的异常,会将软引用对象列入回收范围内进行回收
- 弱引用 WeakReference 被弱引用关联的对象只能够生存到下一次垃圾回收之前
- 虚引用 PhantomReference isEnqueued获取到当前被虚引用关联的对象是否被回收
7. ConcurrentHashMap底层原理
ConcurrentHashMap相比HashMap而言,是多线程安全的,其底层数据与HashMap的数据结构相同,数据结构如下:
(1)ConcurrentHashMap的数据结构(数组+链表+红黑树),桶中的结构可能是链表,也可能是红黑树,红黑树是为了提高查找效率
(2)ConcurrentHashMap继承了AbstractMap抽象类,该抽象类定义了一些基本操作,同时,也实现了ConcurrentMap接口,ConcurrentMap接口也定义了一系列操作,实现了Serializable接口表示ConcurrentHashMap可以被序列化。
(3)内部类
Node类
Node类主要用于存储具体键值对,其子类有ForwardingNode、ReservationNode、TreeNode和TreeBin四个子类。四个子类具体的代码在之后的具体例子中进行分析讲解。
Traverser类
Traverser类主要用于遍历操作,其子类有BaseIterator、KeySpliterator、ValueSpliterator、EntrySpliterator四个类,BaseIterator用于遍历操作。KeySplitertor、ValueSpliterator、EntrySpliterator则用于键、值、键值对的划分。
CollectionView类
CollectionView抽象类主要定义了视图操作,其子类KeySetView、ValueSetView、EntrySetView分别表示键视图、值视图、键值对视图。对视图均可以进行操作。
Segment类
Segment类在JDK1.8中与之前的版本的JDK作用存在很大的差别,JDK1.8下,其在普通的ConcurrentHashMap操作中已经没有失效,其在序列化与反序列化的时候会发挥作用。
CounterCell
CounterCell类主要用于对baseCount的计数。