java集合主要包含两种类型Collection(集合)、Map(图),Collection存储一个元素集合,Map存储键值对,Collection下面分为List、Set、Queue,虚线框的都是接口或者抽象类不可直接使用,实线框中才能直接使用,常用的集合有ArrayList、HashSet、LinkedList、LinkedHashSet、HashMap、LinkedHashMap
==================================================================
ArrayList源码分析
contains方法在ArrayList中实现,源码如下
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
个人理解:contains方法首先判断被比较对象是否为空,如果为空的话则调用Iterator迭代器逐一对比集合中有的元素,如果集合存在元素为空返回true,如果被比较对象不可空同样调用Iterator迭代器逐一对比,相同则返回true,对比方法为equals。
被比较对象equals使用默认Object原生方法比较的是两个元素的内存地址,如果被比较对象有重写equals方法则比较内容。
add方法在ArrayList中实现,源码如下
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//ArrayList扩容判断
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//ArrayList扩容算法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
个人理解:ArrayList集合内部维护的是一个Object数组,add方法首先判断数组大小是否需要扩容,
扩容具体逻辑是是否使用默认构造方法,如果是则和默认数组大小10比较返回最大值,如果不是默认构造方法构造直接返回当前需要的容器大小。具体扩容逻辑在grow方法中,自动扩容1.5倍,如果还不能满足则扩容到Inter.MAX_VALUE-8大小。
ArrayList最大容量为Inter.MAX_VALUE。
toArray方法在Arraylist中实现,源码如下
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
个人理解:System.arraycopy方法是ArrayList中使用非常频繁的方法,是Native静态方法,是一个非常高效的数组拷贝方法。arraycopy第一个参数表示源数组,第二个参数表示源数组要复制的起始位置,第三个参数表示目标数组,第四个参数为目标数组起始位置,第五个参数表示复制源数组的长度。
Iterator迭代器源码如下
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
个人理解:Iterator迭代器在ArrayList中的实现为内部类方式,迭代器操作为不安全线程操作,为了防止出现集合数据不一致,迭起器在每个方法执行前加了checkForComodification验证,判断改变次数是否一致,是否是在迭代器内部进行的数据操作。
LinkedList源码分析
Linked继承了List,LinkedList是一个双向链表,它是由每个node节点组成,每个node节点具有三个属性,分别是item、next、prev,item是当前节点内容,next是当前节点指向的下一个节点地址,prev是上个节点地址。它可以用来实现队列、栈等数据模型。
push方法源码如下
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
add方法源码如下
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
pop方法源码如下
//从头部开始删除
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
//从尾部开始删除
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}