组合模式在JDK源码中的应用
HashMap 是我们使用频率最高的用于映射(键值对)处理的数据类型,本节来看组合模式在 HashMap 中的应用。
HashMap 类的部分源码如下。
说到中间构件就肯定会有规定的存储方式,HashMap 中的存储方式是一个静态内部类的数组 Node<K,V>[] tab,源码如下。
同理,我们常用的 ArrayList 对象也有 addAll() 方法,其参数也是 ArrayList 的父类 Collection,源码如下。
学习完本篇文章后,可以再去回顾一下组合模式的定义和使用场景,说不定收获会更大。
HashMap 类的部分源码如下。
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
...
public void putAll(Map<? extends K, ? extends V> m) {
putMapEntries(m, true);
}
...
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}
...
}
以上是 HashMap 类的简化源码,我们可以看到 putAll( ) 方法中传入的是 Map 对象。这里的 Map 就是一个抽象构件,同时这个构件只支持键值对的存储格式,而 HashMap 是一个中间构件,HashMap 中的 Node 节点就是叶子节点。说到中间构件就肯定会有规定的存储方式,HashMap 中的存储方式是一个静态内部类的数组 Node<K,V>[] tab,源码如下。
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;
}
...
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;
}
...
}
HashTable 也可以看作是一个中间构件,里面的 putAll 方法同样传入的是 Map 对象。关于 Map 接口的关系图如下:

同理,我们常用的 ArrayList 对象也有 addAll() 方法,其参数也是 ArrayList 的父类 Collection,源码如下。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
...
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
...
}
组合对象和被组合对象应该有统一的接口实现或者统一的抽象父类。学习完本篇文章后,可以再去回顾一下组合模式的定义和使用场景,说不定收获会更大。
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算