在Java编程语言中,集合框架是处理数据集合的标准方式,它提供了丰富的接口和实现,使得数据操作变得更加高效和方便。本文将深入解析Java集合框架中的核心数据结构,包括ArrayList和HashMap,并探讨它们的原理与实现。
ArrayList原理与实现
ArrayList是Java集合框架中的一种动态数组实现,它提供了快速的随机访问能力。以下是ArrayList的核心原理和实现:
原理
- 数组实现:ArrayList内部使用数组来存储元素,它可以根据需要动态扩展数组的大小。
- 扩容机制:当数组满时,ArrayList会创建一个新的更大的数组,并将旧数组中的元素复制到新数组中。
- 随机访问:由于是数组实现,ArrayList提供了O(1)时间复杂度的随机访问能力。
实现细节
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.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 = new Object[DEFAULT_CAPACITY];
}
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
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);
}
public E get(int index) {
rangeCheck(index);
return (E) elementData[index];
}
public E set(int index, E element) {
rangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
// 省略其他方法...
}
HashMap原理与实现
HashMap是Java集合框架中的一种基于哈希表的数据结构,它提供了快速的查找和插入操作。以下是HashMap的核心原理和实现:
原理
- 哈希表实现:HashMap内部使用哈希表来存储键值对,它通过键的哈希值来确定元素在表中的位置。
- 冲突解决:当两个键的哈希值相同时,HashMap会使用链表或红黑树来存储这些键值对。
- 负载因子:HashMap通过负载因子来控制哈希表的扩容时机,当负载因子超过阈值时,HashMap会进行扩容。
实现细节
public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 362498820763181265L;
static class Node<K, V> implements Map.Entry<K, V> {
final K key;
V value;
Node<K, V> next;
int hash;
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;
Object k1 = key;
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = value;
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2))) {
return true;
}
}
return false;
}
public final int hashCode() {
return hash ^ (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
}
}
static class EntrySet extends AbstractSet<Map.Entry<K, V>> {
// 省略其他方法...
}
transient Set<Map.Entry<K, V>> entrySet;
transient int size = 0;
transient int threshold;
final float loadFactor;
transient Entry<K, V>[] table;
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int) (DEFAULT_CAPACITY * loadFactor);
table = new Entry[DEFAULT_CAPACITY];
}
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0) {
throw new IllegalArgumentException("Illegal Initial Capacity: " + initialCapacity);
}
if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
throw new IllegalArgumentException("Illegal Load factor: " + loadFactor);
}
this.loadFactor = loadFactor;
threshold = (int) (initialCapacity * loadFactor);
if (initialCapacity == 0) {
table = EMPTY_TABLE;
} else {
table = new Entry[initialCapacity];
}
}
public V put(K key, V value) {
Entry<K, V>[] tab;
int hash, i;
Entry<K, V> p;
if ((tab = table) == null || (tab.length == 0)) {
initTable();
}
if ((hash = key.hashCode()) == 0) {
hash = 1;
}
for (i = (hash & (tab.length - 1)); (p = tab[i]) != null; i = (hash & (tab.length - 1))) {
if (p.hash == hash && ((key == p.key) || (key != null && key.equals(p.key)))) {
V oldValue = p.value;
p.value = value;
return oldValue;
}
}
modCount++;
if (++size > threshold) {
resize();
}
tab[i] = new Entry<>(hash, key, value, null);
return null;
}
private void initTable() {
threshold = (int) (loadFactor * DEFAULT_CAPACITY);
table = new Entry[threshold];
}
private void resize() {
Entry<K, V>[] oldTable = table;
int oldCapacity = oldTable.length;
int newCapacity = oldCapacity << 1;
if (newCapacity - threshold < 0) {
newCapacity = threshold;
}
if (newCapacity - MAX_ARRAY_SIZE > 0) {
newCapacity = hugeCapacity(threshold);
}
Entry<K, V>[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int) (loadFactor * newCapacity);
}
private void transfer(Entry<K, V>[] newTable) {
int newCapacity = newTable.length;
for (Entry<K, V> e : oldTable) {
while (e != null) {
Entry<K, V> next = e.next;
int i = e.hash & (newCapacity - 1);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
// 省略其他方法...
}
总结
通过以上解析,我们可以了解到ArrayList和HashMap的原理与实现。ArrayList通过数组实现,提供了快速的随机访问能力;而HashMap通过哈希表实现,提供了快速的查找和插入操作。了解这些数据结构的内部机制,有助于我们更好地使用Java集合框架,提高代码的效率和质量。
