组合模式在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
- 大数据
- 云计算