前些天被问HashMap实现原理,表示都没怎么看过源码。。。就想从头看一遍。
java集合工具包java.util.。大致关系如下
/**
* |
* |Collection
* | --AbstractCollection
* | --AbstractList
* | --AbstractSet
* | --AbstractQueue
* | --List :可重复,有存储顺序
* | --AbstractList
* | --Vector :和ArrayList一样,但线程安全,所以效率低
* | --Stack
* | --AbstractSequentialList
* | --LinkedList :链表,查找慢(查找需要依次遍历),增删快(当前位置前后元素相连即可)
* | --ArrayList :底层数组,查找快(数组可直接按照索引查找快),增删慢(涉及增容,拷贝)
* | --CopyOnWriteArrayList
* | --Set :不可重复,无存储顺序
* | --AbstractSet
* | --HashSet :不需要排序使用效率高于TreeSet
* | --LinkedHashSet :需要保留存储顺序,又要过滤重复元素时使用
* | --TreeSet :需要将元素排序时使用
* | --SortedSet
* | --NavigableSet
* | --Queue
* | --Deque
* | --AbstractQueue
* | --PriorityQueue
* |Map
* | --ConcurrentMap
* | --ConcurrentHashMap
* | --SortedMap
* | --NavigableMap
* | --TreeMap
* | --AbstractMap
* | --HashMap
* | --LinkedHashMap
* | --WeakHashMap
* | --IdentityHashMap
* | --TreeMap
* | --EnumMap
*/
主要分为Collection和Map两部分
Iterator
Collection集成Iterable接口,首先看Iterable接口,里面只有一个方法:
Iterator<T> iterator();
该方法返回一个Iterator迭代器,是遍历集合的工具,迭代器指向的位置是元素之前的位置(以下称为游标)
Iterator接口共有三个方法,分别为:是否存在当前游标的下一个元素,获取下一个元素,删除当前元素
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
使用类似如下步骤可以迭代输出集合中的数据:
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
另外:Iterator在访问集合数据时,使用fast-fail机制,即当某一线程A通过iterator遍历集合时,若该集合内容被其他线程改变,那A遍历集合时会抛出ConcurrentModificationException异常。例如HashMap中通过比较modCount(该值每次修改集合后会+1)和expectedModCount(在使用HashIterator时设置=modCount)是否相等,不等抛出该异常。
可以使用CopyOnWriteArrayList代替ArrayList,ConcurrentHashMap代替HashMap;
或者使用Collections.synchronizedLsit(list)方法.
for-each循环内部也使用的Iterator遍历
ListIterator:
该接口继承Iterator,适用于List及其子类,并且增加了6个方法,
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext(); //判断游标后是否有元素
E next(); //返回游标后面一个元素,并且游标后移一位
boolean hasPrevious(); //判断游标前是否有元素
E previous(); //返回游标前面的元素,并且游标向前移动一位
int nextIndex(); //返回游标后面的索引位置
int previousIndex(); //返回游标前面的索引位置
void remove(); //删除迭代器操作的最后一个元素
void set(E e); //更新迭代器最后一次操作的元素
void add(E e); //在游标前面插入元素
}
在LIst子类中有各自的ListIterator具体实现类.
Collection:
collection接口有两个分支,List和Set。这两个也都是接口,List是由存储顺序,可重复;Set无存储顺序,不可重复。
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o); //是否包含指定元素
Iterator<E> iterator(); //获取迭代器
Object[] toArray(); //返回一个包含集合中所有元素的数组
<T> T[] toArray(T[] a); //返回一个包含集合中所有元素的数组,运行时根据集合类型指定数组的类型
boolean add(E e); //添加元素
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c); //保留本集合和C集合共有的
void clear();
boolean equals(Object o);
int hashCode();
}
List:
public interface List<E> extends Collection<E> {
boolean isEmpty();
boolean contains(Object o); //判断是否包含o
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o); //需重写,因为Object默认是地址比较
int hashCode(); //需重写
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o); //返回指定元素第一次出现的位置
int lastIndexOf(Object o); 返回指定元素最后一次出现的位置(倒叙遍历)
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index); //指定了游标的位置
List<E> subList(int fromIndex, int toIndex); //范围查询,左闭右开
}
list是一个序列,在内存中开辟一段连续的空间,将空间地址与索引对应,在插入元素时,根据索引排列。
Set:
set是没有重复元素的集合,API与Collection一样。
AbstractCollection:
是Collection的实现类,包含了一些具体实现方法以及几个抽象方法,是一个抽象类,AbstractSet和AbstractList继承它。
包含以下两个抽象方法:
public abstract Iterator<E> iterator();
public abstract int size();
默认不支持添加单个元素,会报错,因此如果子类是可添加的,需实现add。
public boolean add(E e) {
throw new UnsupportedOperationException();
}
默认构造函数
protected AbstractCollection() {
}
判断是否为空
public boolean isEmpty() {
return size() == 0;
}
判断是否包含元素:使用子类的迭代器Iterator遍历,存在是null或者不是null两种情况(说明支持存null),如果有返回true
public boolean contains(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))
return true;
}
return false;
}
转换成Object[]数组:使用Iterator遍历赋值给一个新建的数组。
这个方法的实现还确保了即使在迭代器期间修改了集合。比如说size的返回的大小不对还是会根据迭代器迭代到的元素的数量得到正确的数组
public Object[] toArray() {
// Estimate size of array; be prepared to see more or fewer elements
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) // 如果迭代器的实际大小比size小,则使用Array.copyOf(r,i)截断当前的数组,然后直接返回
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r; //如果size小于迭代器的,则调用finishToArray()
}
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length; //当前迭代的元素数量
while (it.hasNext()) {
int cap = r.length; //当前数组的大小
if (i == cap) { //如果两个值一样,说明需要加大数组的长度,即增加cap。这里增加了0.5cap+1
int newCap = cap + (cap >> 1) + 1;
if (newCap - MAX_ARRAY_SIZE > 0) //判断是否超过VM最大界限
newCap = hugeCapacity(cap + 1); //超过则调用该函数调整大小
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next(); //将迭代器下一个元素放入数组,迭代数量+1
}
return (i == r.length) ? r : Arrays.copyOf(r, i); //结束时根据已经迭代的元素数i,来复制当前数组到一个新的数组
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//AbstractCollection中定义
private static int hugeCapacity(int minCapacity) {//用于确定数组极限的值
if (minCapacity < 0) // overflow
throw new OutOfMemoryError
("Required array size too large");
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
第二个 toArray
这个方法将对象先试图填充到给定的数组a中,如果a的数组不够用了,则新建一个新数组来保存集合中的元素
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
T[] r = a.length >= size ? a : //判断添加的数组a与原list长度哪个大
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size); //创建一个新的、类型与a一样的、长度为size的数组
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) { //迭代器迭代完成
if (a == r) { //如果r引用的就是a
r[i] = null; //i位为0
} else if (a.length < i) { //a的长度小于i,说明放不进a,则返回的是自建数组,对r后面的元素截取就可以了
return Arrays.copyOf(r, i);
} else { //说明a数组是足够大的
System.arraycopy(r, 0, a, 0, i); //将r中的元素放入到a中,
if (a.length > i) {
a[i] = null;
}
}
return a;
}
r[i] = (T)it.next();
}
// more elements than expected
return it.hasNext() ? finishToArray(r, it) : r;
}
移除某一元素,使用Iterator
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
比较是否包含某一集合全部元素 addAll和该方法相似
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
保留两个集合元素相同的 removeAll和该方法相似
public boolean retainAll(Collection<?> c) {
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
toString
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
AbstractList:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>
该抽象类实现了List的一些操作方法,但不支持添加和替换
实现了AbstractCollection的其中一个抽象方法interator()
public Iterator<E> iterator() {
return new Itr();
}
Itr是一个实现Iterator接口的内部类。
如果子类要使用add,set,remove方法,则需要重写,否则会报错UnsupportedOperationException
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
该类提供一个抽象方法get,用于子类实现
abstract public E get(int index);
AbstractList提供 Iterator, ListIterator 迭代器的实现类,分别为 Itr, ListItr;ListItr继承Itr
ListItr使用如下方法获取
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);//用来检查索引是否超过范围 <0 >size
return new ListItr(index);
}
Itr类:只实现了hasNext ,next ,remove方法
private class Itr implements Iterator<E> {
int cursor = 0;//游标
int lastRet = -1;//上一次迭代到的位置,用完后置-1
int expectedModCount = modCount;//判断并发修改
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();//判断并发修改
try {
int i = cursor;
E next = get(i); //调用子类实现的get方法
lastRet = i; //由迭代操作的话,会记录上一次迭代的位置
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);//需要子类实现remove,当前类会抛异常
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
ListItr:多了向前previous,set,add方法
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index; //指定游标位置
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i; //上次操作的位置 = i;游标 = i
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {//下一个位置
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e); //子类方法,上次的位置还要在其中查询是否为-1
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
ActractList中的indexof:获得o所在的第一次出现的位置
public int indexOf(Object o) {
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
public int lastIndexOf(Object o) { //最后一次出现的位置
ListIterator<E> it = listIterator(size());//先得到迭代器最后一个位置
if (o==null) {
while (it.hasPrevious())//向前
if (it.previous()==null)
return it.nextIndex();
} else {
while (it.hasPrevious())
if (o.equals(it.previous()))
return it.nextIndex();
}
return -1;
}
移除全部clear, 和移除制定范围removrRage方法
public void clear() {
removeRange(0, size());
}
protected void removeRange(int fromIndex, int toIndex) {
ListIterator<E> it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i<n; i++) {
it.next();
it.remove();
}
}
equals和hashcode
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while (e1.hasNext() && e2.hasNext()) { //同时迭代当前集合和o集合,判断是否全都相同
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}
subList范围查询
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
出现三个类
public interface RandomAccess {
}
RandomAccess是一个空的接口,用来标识支持 随机访问(与顺序访问相比),效率更高。例如ArrayList就是,它的get(i),set()时间复杂度O(1)。而LinkedList就只能按顺序访问。
通常在操作List会先判断是否支持随机访问,是否是RandomAccess的实例,如果是,比如在遍历中就使用get(),而不是Iterator,因为前者更快。
RandomAccessSubList: 与SubList相比,就多一个RandomAccess
class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
super(list, fromIndex, toIndex);
}
public List<E> subList(int fromIndex, int toIndex) {
return new RandomAccessSubList<>(this, fromIndex, toIndex);
}
}
SubList:
class SubList<E> extends AbstractList<E> {
private final AbstractList<E> l;
private final int offset;
private int size;
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list;
offset = fromIndex;
size = toIndex - fromIndex;
this.modCount = l.modCount;
}
public E set(int index, E element) {
rangeCheck(index);
checkForComodification();
return l.set(index+offset, element);
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
public int size() {
checkForComodification();
return size;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
checkForComodification();
l.add(index+offset, element);
this.modCount = l.modCount;
size++;
}
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = l.remove(index+offset);
this.modCount = l.modCount;
size--;
return result;
}
protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
l.removeRange(fromIndex+offset, toIndex+offset);
this.modCount = l.modCount;
size -= (toIndex-fromIndex);
}
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;
checkForComodification();
l.addAll(offset+index, c);
this.modCount = l.modCount;
size += cSize;
return true;
}
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
return new ListIterator<E>() {
private final ListIterator<E> i = l.listIterator(index+offset);
public boolean hasNext() {
return nextIndex() < size;
}
public E next() {
if (hasNext())
return i.next();
else
throw new NoSuchElementException();
}
public boolean hasPrevious() {
return previousIndex() >= 0;
}
public E previous() {
if (hasPrevious())
return i.previous();
else
throw new NoSuchElementException();
}
public int nextIndex() {
return i.nextIndex() - offset;
}
public int previousIndex() {
return i.previousIndex() - offset;
}
public void remove() {
i.remove();
SubList.this.modCount = l.modCount;
size--;
}
public void set(E e) {
i.set(e);
}
public void add(E e) {
i.add(e);
SubList.this.modCount = l.modCount;
size++;
}
};
}
public List<E> subList(int fromIndex, int toIndex) {
return new SubList<>(this, fromIndex, toIndex);
}
private void rangeCheck(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
private void checkForComodification() {
if (this.modCount != l.modCount)
throw new ConcurrentModificationException();
}
}
使用的都是父类的方法和数据。