OpenJDK8 源码学习(二)Map

Map接口

包位置 (java.util.Map)
public interface Map<K,V> {

    int size();   					     // 键值对对数
    boolean isEmpty();  				 // 是否为空
    boolean containsKey(Object key);     // 是否包含某键
    boolean containsValue(Object value); // 是否包含某值
    V get(Object key);                   // 根据键取值
    
    // 修改操作
    V put(K key, V value);  	// 添加键值对
    V remove(Object key);       // 移除某键对应的键值对

    // 批量操作
    void putAll(Map<? extends K, ? extends V> m);   // 从指定的map中复制所有的键值对并添加
    void clear();   								// 清空当前map中的所有键值对
    Set<K> keySet();    			 	 // 返回map中键的集合(不可在通过该集合迭代map时,对map进行改动)
    Collection<V> values(); 			 // 返回值的集合(不可在通过该集合迭代map时,对map进行改动)
    Set<Map.Entry<K, V>> entrySet();     // 返回键值对的集合

    interface Entry<K,V> {...}
    
    boolean equals(Object o);
    int hashCode();
	
    // 默认实现方法
    ...
}

Map接口实现

注意是Hashtable,不是HashTable, 这里面有历史遗留问题。

1.Hashtable(java.util.HashTable)

public class Hashtable<K,V>
	extends Dictionary<K,V>                                 // 继承Dictionary父类
	implements Map<K,V>, Cloneable, java.io.Serializable {  // 实现Map接口、Cloneable接口、序列化接口

    private transient Entry<?,?>[] table;					// 数组存放 hashtable 中键值对数据
    private transient int count;							// 键值对对数 
    private int threshold;									// 设定的阈值(当count超过设定的阈值时,hashtable扩容)
    private float loadFactor;								// 负载系数(默认情况下0.75f)
    private transient int modCount = 0; 					// 记录hashtable结构改动次数(包括键值对数目变动、内部结构改动)
    private static final long serialVersionUID = 1421746759512286392L;
	
	**// 构造函数(默认情况下,容量设定为11,负载系数设定为0.75f) **
    public Hashtable(int initialCapacity, float loadFactor) { ...}	// 初始化容量和负载系数,阈值=容量*负载系数
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }
    public Hashtable() {	
        this(11, 0.75f);
    }
    public Hashtable(Map<? extends K, ? extends V> t) {... } 	// 以t中的键值对初始化,容量为max(2*t大小, 11), 负载系数为默认值
    
    public synchronized int size() {...}  		 				// 键值对数目
    public synchronized boolean isEmpty() {...} 				// 是否为空
    public synchronized Enumeration<K> keys() {...}
    public synchronized Enumeration<V> elements() {...}
    public synchronized boolean contains(Object value) {...}	// 是否存在value与hashtable中某一键值对的值满足equals()
    public boolean containsValue(Object value) {... }			// 调用了上一个函数
    public synchronized boolean containsKey(Object key) {... }	// 根据key的hash值去判断hashtable中是否存在相对应的键(hash值一致,且同时要满足equals())

    public synchronized V get(Object key) {...}						// 用键取值,不存在相同的键则返回null
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 可分配的hashtable最大容量
    protected void rehash() {... } 						// 键值对数目超过阈值时调用,完成扩容(2*旧容量+1)及对旧数据的复制
   
    private void addEntry(int hash, K key, V value, int index) {... }
    public synchronized V put(K key, V value) {... }	// 添加键值对(键、值均不为空,否则报空指针异常),若键已存在,更新值并返回旧的值,内部调用上一函数
    public synchronized V remove(Object key) {... }		// 根据键删除键值对(键不能为null,否则报空指针异常),若键存在,删除并返回原来对应值;若键不存在且不为空,返回null
    public synchronized void putAll(Map<? extends K, ? extends V> t) {... }	// 逐一添加map t 中的键值对
    public synchronized void clear() {...}				// 清空键值对,并把键值对数目清零
    public synchronized Object clone() {... } 			// 拷贝,但内部的键和值都只是浅拷贝
    public synchronized String toString() {...}
    private <T> Enumeration<T> getEnumeration(int type) {...}		// 获取枚举类对象,type
    private <T> Iterator<T> getIterator(int type) {... }			// 获取枚举类对象的迭代器

    private transient volatile Set<K> keySet; 					// 键组成的集合
    private transient volatile Set<Map.Entry<K,V>> entrySet; 	// 键值对组成的集合
    private transient volatile Collection<V> values;			// 值组成的集合
    public Set<K> keySet() {...}								// 返回键组成的集合
    public Set<Map.Entry<K,V>> entrySet() {...}					// ...
    public Collection<V> values() {...}						    // ...

    public synchronized boolean equals(Object o) {...}		// map类型的equals()方法
    public synchronized int hashCode() {...}				// 
	
	// .....
}

2.HashMap(java.util.HashMap)

public class HashMap<K,V> 
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
    private static final long serialVersionUID = 362498820763181265L;
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;       	// 默认的初始化容量16
    static final int MAXIMUM_CAPACITY = 1 << 30;            	// 最大的容量2^30
    static final float DEFAULT_LOAD_FACTOR = 0.75f;        		// 默认的负载系数0.75f
    static final int TREEIFY_THRESHOLD = 8;         // 将链表转为红黑树存储的阈值(对应于一个hash值上冲突元素个数)
    static final int UNTREEIFY_THRESHOLD = 6;       // 将红黑树转为链表存储的阈值
    static final int MIN_TREEIFY_CAPACITY = 64;     // 使用红黑树时hashmap的最小容量,即只有大于该阈值时,才启用链表->红黑树转换;

    static class Node<K,V> implements Map.Entry<K,V> {...}		// 存放键值对的节点类型
    static final int hash(Object key) {...}				// 哈希函数,高16位与低16位异或操作,能够降低冲突
    static final int tableSizeFor(int cap) {... }		// 根据给定的目标容量,返回可行的2倍数容量
    transient Node<K,V>[] table;        				// 数组存放hashmap的节点键值对数据
    transient Set<Map.Entry<K,V>> entrySet; 			// 键值对集合
    transient int size;     							// 键值对数目
    transient int modCount;     	// 记录hashmap结构改动次数(包括键值对数目变动、内部结构改动)
    int threshold;      			// 阈值
    final float loadFactor;     	// 负载系数
    
    // 构造函数
    public HashMap(int initialCapacity, float loadFactor) {...}         // 指定初始容量和负载系数
    public HashMap(int initialCapacity) {...}
    public HashMap() {...}
    public HashMap(Map<? extends K, ? extends V> m) {...}

    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {...}
    public int size() {...}        						// 返回键值对数目
    public boolean isEmpty() {...}         				// 判断是否为空
    public V get(Object key) {...}     					// 根据键返回值,不存在返回null

    final Node<K,V> getNode(int hash, Object key) {...} // 根据hash值和键查找键值对,不存在则为null
    public boolean containsKey(Object key) {...}
    public V put(K key, V value) {...}      			// 往HashMap添加键值对,调用下一个函数
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {...}        		 	// 添加节点,若onlyIfAbsent为真,则不改变原有值,否则根据hash和key更新值,不存在则返回null;添加后数量超过阈值则扩容
    final Node<K,V>[] resize() {...}    				// 扩容,(初始化/扩容到2的倍数)
    final void treeifyBin(Node<K,V>[] tab, int hash) {...}          // 对hashmap中某个hash桶进行树形化存储(满足条件的话)
    public void putAll(Map<? extends K, ? extends V> m) {...}       // 将map中的键值对添入HashMap
    public V remove(Object key) {...}       			// 根据键删除键值对节点,返回旧值;不存在返回null
    final Node<K,V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) {...}
    public void clear() {...}       					// 清空HashMap
    public boolean containsValue(Object value) {...}    // 判断是否存在对应值的键值对

    public Set<K> keySet() {...}            // 返回键组成的集合
    public Collection<V> values() {...}     // 返回值组成的集合
    public Set<Map.Entry<K,V>> entrySet() { ...}        // 返回键值对组成的集合
	
	//...
}

3.Hashtable和HashMap比较

  1. Hashtable 为数组+链表结构,HashMap为数组+链表/红黑树结构(优化查询)
  2. Hashtable 中键、值都不准为null,运行时报空指针异常;HashMap 支持键、值为null
  3. Hashtable 默认初始容量为11,随后以2*旧容量+1扩容;
    HashMap默认初始容量为16,随后以 2*旧容量扩容,扩容后始终为2的倍数;
    (关于Hashtable为什么要+1,是因为采用了hash+取模方式寻找桶,扩充后容量为素数/奇数会利于数据的均匀分布)
  4. Hashtable 方法都用synchronized 修饰符进行方法同步,因此线程安全,但同时影响了效率;HashMap非线程安全,但是效率高,并发环境下可以使用ConcurrentHashMap*(位于java. util. concurrent包)*
  5. 内部迭代器的不同,Hashtable的Enumeration 迭代器非fail-fast(详解见此);而HashMap的Iterator迭代器满足,因此当有其它线程改变了HashMap的结构(增加或者移除元素),会抛出ConcurrentModificationException。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值