一、List集合
1、ArrayList
下面是有关ArrayList容量的源码
private static final int DEFAULT_CAPACITY = 10;//默认容量10
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认空数组
transient Object[] elementData;
private int size;//默认为0
public ArrayList() {//无参构造方法,Object数组长度为0
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private void ensureCapacityInternal(int minCapacity) {
//此方法目的是在没有指定集合容量时,第一次add时给集合分配10的默认空间
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
public ArrayList(int initialCapacity) {//有参构造方法,Object数组长度为initialCapacity
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//数组集合最大长度2^31-1-8
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);
}
在上面的代码中由 int newCapacity = oldCapacity + (oldCapacity >> 1);可知集合容量是以1.5倍来扩容的,而且若使用无参构造方法实例化集合,那么集合的默认长度为10,也就是说扩容时是以
10,15,22,33, 50 , 75 , 112 。。。。来进行。
若使用有参构造方法指定初始容量,例如100,就会以100,150,220,330,750。。。来进行。
2、LinkedList
LinkedList,见名知意底层是由链表来实现的集合。
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
两个构造方法都没有涉及容量,其实很容易理解,在JDK1.5之后LinkedList就采用了双向链表来实现,没有初始长度,没有容量限制,只要在链表最后一直添加就行了。
另外,此集合内存储的是一个个“节点”:
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++;
}
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++;
}
private static class Node<E> {//节点定义
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
二、Set集合与Map集合
1、HashSet
HashSet:HashMap中k-v中的k部分,所以我们直接分析HahMap集合
一般来说如果想要查看一个集合的初识容量只需要分析集合中第一次add,或是put方法即可,
add方法的跳转过程是:HashSet中的add方法→HashMap中的put方法→HashMap中的putVal
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
上面的tab = resize()即是对数组的初始化,找到resize()
//resize代码过长,已经超出作者能力,不再具体分析,下面只介绍初识容量已经扩容机制
newCap = oldCap << 1//新容量是旧容量的二倍
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//DEFAULT_INITIAL_CAPACITY 值为16
newCap = DEFAULT_INITIAL_CAPACITY;//数组容量为16
static final float DEFAULT_LOAD_FACTOR = 0.75f;//加载因子
加载因子作用是标志一个阈值,该值为自身容量*加载因子,若达到阈值则扩容。
2、HashTable
初始化容量的方法:
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
// overflow-conscious code
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
}
}
}
可以看到int newCapacity = (oldCapacity << 1) + 1;旧容量*2+1为新容量
public Hashtable() {
this(11, 0.75f);
}
public Hashtable(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal Load: "+loadFactor);
if (initialCapacity==0)
initialCapacity = 1;
this.loadFactor = loadFactor;
table = new Entry<?,?>[initialCapacity];
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}
观察上述代码可见若不指定则HashTable初始长度为11.