Java集合框架是Java编程语言中一个非常重要的部分,它提供了操作集合的强大工具,使得我们能够高效地存储和访问数据。本文将带你深入探索Java集合框架的源码,从基础的入门知识到高级的编程技巧,逐步掌握这个强大的框架。
一、Java集合框架概述
Java集合框架提供了各种数据结构的实现,包括列表、集合、映射和队列等。这些数据结构在Java编程中无处不在,无论是日常的编程任务还是复杂的系统开发,都离不开它们。
1.1 集合框架的基本概念
在Java集合框架中,有几个基本的概念需要了解:
- 集合(Collection):用于存储一组元素,如List、Set和Queue等。
- 映射(Map):用于存储键值对,如HashMap、TreeMap等。
- 队列(Queue):用于存储元素队列,如ArrayDeque、LinkedList等。
- 栈(Stack):实际上是Queue的一种特殊实现,用于存储元素的LIFO(后进先出)结构。
1.2 集合框架的类图
Java集合框架的类图展示了各种集合之间的关系和继承关系,了解这个类图对于深入理解集合框架非常有帮助。
二、常用集合类源码分析
在Java集合框架中,有许多常用的集合类,下面我们以ArrayList和HashMap为例,分析它们的源码。
2.1 ArrayList源码分析
ArrayList是一个动态数组,它提供了快速的随机访问,但是插入和删除操作可能比较慢。以下是ArrayList的主要源码:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private transient Object[] elementData;
private int size;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ARRAY;
}
public ArrayList(int initialCapacity) {
if (initialCapacity >= 0) {
this.elementData = new Object[initialCapacity];
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
public E get(int index) {
if (index >= size || index < 0) {
throw new IndexOutOfBoundsException();
}
return (E) elementData[index];
}
public E set(int index, E element) {
E oldValue = get(index);
elementData[index] = element;
return oldValue;
}
public void add(int index, E element) {
if (index > size || index < 0) {
throw new IndexOutOfBoundsException();
}
ensureCapacityInternal(size + 1);
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element;
size++;
}
public E remove(int index) {
E oldValue = get(index);
int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
elementData[--size] = null;
return oldValue;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ARRAY) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
if (minCapacity - elementData.length > 0) {
grow(minCapacity);
}
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
if (newCapacity - MAX_ARRAY_SIZE > 0) {
newCapacity = hugeCapacity(minCapacity);
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) {
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
}
2.2 HashMap源码分析
HashMap是一个基于散列表实现的Map接口,它提供了快速的查找和插入操作。以下是HashMap的主要源码:
public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, Serializable {
private static final long serialVersionUID = 362498820763181265L;
static class Node<K, V> implements Map.Entry<K, V> {
final int hash;
final K key;
V value;
Node<K, V> next;
Node(int hash, K key, V value, Node<K, V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() {
return key;
}
public final V getValue() {
return value;
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
}
Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
if (e.getKey() == null ? key == null : !e.getKey().equals(key)) {
return false;
}
if (e.getValue() == null ? value == null : !e.getValue().equals(value)) {
return false;
}
return true;
}
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
}
transient Entry<K, V>[] table;
transient int size;
transient int modCount;
int threshold;
final float loadFactor;
public HashMap() {
this.loadFactor = 0.75f;
this.threshold = (int) (INITIAL_CAPACITY * loadFactor);
this.table = (Entry<K, V>[]) new Entry[INITIAL_CAPACITY];
}
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
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
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
private void resize() {
int oldCapacity = table.length;
int newCapacity = oldCapacity << 1;
if (newCapacity - threshold < 0)
threshold = newCapacity - 1;
Entry<K, V>[] newTable = (Entry<K, V>[]) new Entry[newCapacity];
transfer(newTable);
table = newTable;
}
private void transfer(Entry<K, V>[] newTable) {
int newCapacity = newTable.length;
for (Entry<K, V> e : table) {
while (e != null) {
Entry<K, V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
private static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
private int indexFor(int h, int n) {
return h & (n - 1);
}
static final class TreeNode<K, V> extends LinkedHashMap.Entry<K, V> {
TreeNode<K, V> parent; TreeNode<K, V> left;
TreeNode<K, V> right; TreeNode<K, V> prev; TreeNode<K, V> next;
int hash; int count; V value;
TreeNode(int hash, K key, V val, TreeNode<K, V> parent) {
super(hash, key, val, parent);
}
TreeNode(int hash, K key, V val, Node<K, V> parent) {
super(hash, key, val, parent);
this.parent = parent;
}
TreeNode(int hash, K key, V val, Node<K, V> parent, Node<K, V> left,
Node<K, V> right) {
super(hash, key, val, parent);
left = left;
right = right;
}
Node<K, V> putTreeVal(Map<K, V> map, Node<K, V>[] tab, int h, K k, V v) {
Class<?> kc = null;
boolean p = true;
for (TreeNode<K, V> b = root; b != null; ) {
TreeNode<K, V> node = b;
K k2 = node.key;
int h2 = k2 == null ? 0 : k2.hashCode();
if (h == h2) {
if (k == k2)
return node;
if (kc == null && (kc = comparableClassFor(k)) != null) {
return compareComparables(kc, k, k2);
}
p = false;
}
TreeNode<K, V> lo = node.left;
TreeNode<K, V> hi = node.right;
intPHI = (h ^ h2) >>> 13;
if ((PHI & 1) == 0) {
b = lo;
} else if ((PHI & 2) == 0) {
b = hi;
} else {
b = node;
}
}
TreeNode<K, V> newNode = newNode(h, k, v, p);
return insert(newNode, map, into, obfkc);
}
TreeNode<K, V> insert(Node<K, V> into, Map<K, V> map, boolean obfkc) {
TreeNode<K, V> root = (parent != null) ? root : this;
TreeNode<K, V> node = root;
int h = into.hash;
K k = into.key;
intPHI = (h ^ h2) >>> 13;
if ((PHI & 1) == 0) {
b = lo;
} else if ((PHI & 2) == 0) {
b = hi;
} else {
b = node;
}
}
}
private static final class Entry<K, V> extends HashMap.Node<K, V> {
HashMap.Entry<K, V> before, after;
Entry(int h, K k, V v, HashMap.Entry<K, V> p) {
super(h, k, v, p);
}
}
}
三、深入理解集合框架原理
在掌握了基本的集合类源码之后,我们需要深入理解集合框架的原理,包括以下几个方面:
3.1 集合框架的泛型机制
Java集合框架的泛型机制使得我们能够更安全地操作集合,避免在运行时出现类型转换错误。了解泛型的原理对于深入理解集合框架非常有帮助。
3.2 集合框架的并发控制
Java集合框架提供了多种并发控制机制,如Collections.synchronizedList()和Collections.synchronizedMap()等。了解这些机制的工作原理可以帮助我们在多线程环境下安全地使用集合。
3.3 集合框架的性能优化
Java集合框架的每个集合类都有其适用的场景,了解各个集合类的性能特点可以帮助我们选择最合适的集合类,从而提高程序的性能。
四、总结
Java集合框架是Java编程语言中一个非常重要的部分,它提供了操作集合的强大工具。通过本文的学习,我们不仅掌握了基本的集合类源码,还深入理解了集合框架的原理和性能优化。希望这篇文章能够帮助你更好地掌握Java集合框架,在今后的编程工作中发挥其强大的作用。
