集合框架主要包括两种类型的容器,
一种是集合(Collection),存储一个元素集合,
另一种是图(Map),存储键/值对映射。
Collection接口又有3种子类型,List、Set和Queue,再下面是一些抽象类,最后是具体实现类,常用的有ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap等等。
1、List:
允许重复的有序集合,List接口主要是增加了面向位置的操作
//如果内存不够,开辟新内存:
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//>>右移一位,相当于除以2
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
所以当内存不够时,会开辟原有内存的1.5倍。
ArrayList适合尾部改动的情况
LinkList适合中间改动的情况
2、set:
不包含重复的元素
Set接口有三个具体实现类,分别是散列集HashSet、链式散列集LinkedHashSet和树形集TreeSet。
在HashSet中,内存不够怎么办:假设10的初始容量,0.7的加载因子,当内存达到7时,内存就会变为20。(默认初始容量为16和加载因子0.75)
这几种set的区别是底层实现不同,导致性能特性不同:HashSet是数组(HashMap实现),LinkedHashSet是链表,TreeSet是树。
然后数组的特性就是内存固定,每次快用完了需新开辟空间,再把旧的复制过去。再是中途插入删除,后面所有的元素都要移动,所以很影响效率。但是有索引,所以读取查找效率较高
链表的特性是插入删除很方便。
树则是在排序上有优势
3、Queue
队列是一种先进先出的数据结构,元素在队列末尾添加,在队列头部删除。Queue接口扩展自Collection,并提供插入、提取、检验等操作。
接口Deque,是一个扩展自Queue的双端队列,它支持在两端插入和删除元素,因为LinkedList类实现了Deque接口,所以通常我们可以使用LinkedList来创建一个队列。PriorityQueue类实现了一个优先队列,优先队列中元素被赋予优先级,拥有高优先级的先被删除。
4、HashMap
采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。
JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。(百度了一下红黑树:类似二叉平衡树,因为平衡特性使得最坏的情况都有较高效率。之后还要好好细学红黑树)
5、LinkedHashMap
继承HashMap,但是因为是链表实现,所以可以记录顺序
6、TreeMap
基于红黑树数据结构(所以待我学完基础,第一件事就是要学红黑树)。适合索引排序
如果更新图时不需要保持图中元素的顺序,就使用HashMap,如果需要保持图中元素的插入顺序或者访问顺序,就使用LinkedHashMap,如果需要使图按照键值排序,就使用TreeMap。
7、Vector
与ArrayList基本一致,Vector使用了关键字synchronized将访问和修改向量的方法都变成同步,支持多线程,但是在查找、插入、删除都很慢
8、Stack
栈类,特征是先进后出。只在栈顶操作,记录栈顶位置。
9、HashTable
存储键值对,继承Dictionary,线程安全,key和value都不可以为null。
Vector、Stack和HashTable效率都较其他低,但是均线程安全
10、ConcurrentHashMap
Jdk1.5之后出现,比HashMap线程安全、比HashTable效率高近16倍。Hashtable相当于是给整个table加了锁,而ConcurrentHashMap则优化了锁的粒度,我粗略看了下别人贴的源码,使用Segment各层级来细化锁。这个也要在之后好好看看源码分析
11、CopyOnWriteArrayList
CopyOnWriteArrayList即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。是一个线程安全的List接口的实现,它使用了ReentrantLock锁在添加的时候是需要加,否则多线程写的时候会Copy出N个副本出来
但是有两个问题:1、写操作时内存占用过高 2、数据不实时一致
总结一下:
1、红黑树不懂,引申到HashMap、TreeMap的底层和源码都不懂
2、Hash碰撞没有深究
3、ConcurrentHashMap是如何加锁的,也不搞明白
入门了再回头仔细分析