* |Map
* | --ConcurrentMap
* | --ConcurrentHashMap
* | --SortedMap
* | --NavigableMap
* | --TreeMap
* | --AbstractMap
* | --HashMap
* | --LinkedHashMap
* | --WeakHashMap
* | --IdentityHashMap
* | --TreeMap
* | --EnumMap
Map是映射接口,里面存储的是键值对。
- SortedMap 是继承于Map的接口。SortedMap中的内容是排序的键值对,排序的方法是通过比较器(Comparator)。
- NavigableMap是继承于SortedMap的接口。相比于SortedMap,NavigableMap有一系列的导航方法;如”获取大于/等于某对象的键值对”、“获取小于/等于某对象的键值对”等等。
- TreeMap 继承于AbstractMap,且实现了NavigableMap接口;因此,TreeMap中的内容是“有序的键值对”
- HashMap 继承于AbstractMap,但没实现NavigableMap接口;因此,HashMap的内容是“键值对,但不保证次序”
- WeakHashMap 继承于AbstractMap。它和HashMap的键类型不同,WeakHashMap的键是“弱键”。
1.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);
Set<K> keySet();//获得所有键
Set<Map.Entry<K, V>> entrySet();//返回此映射中包含的映射关系的Set视图
int hashCode();
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
}
}
- KeySet 是一个 Map 中键(key)的集合,以 Set 的形式保存,不允许重复,因此键存储的对象需要重写 equals() 和hashCode() 方法。
- Values 是一个 Map 中值 (value) 的集合,以 Collection 的形式保存,因此可以重复。
- Entry是Map的内部接口,表示键值对的映射。Map通过keySet()获取Map.Entry的键值对集合,保存在Set中,通过该集合实现对键值对的操作,所以Entry也不能重复。
Map的3种遍历方式:
1.使用 keySet 遍历:
Set set = map.keySet();
for (Object key : set) {
System.out.println(map.get(key));
}
2.使用 values 遍历:
Collection values = map.values();
Iterator iterator = values.iterator();
while (iterator.hasNext()){
System.out.println("value " + iterator.next());
}
3.使用 Entry 遍历
Set entrySet = map.entrySet();
for (Object o : entrySet) {
Map.Entry entry = (Map.Entry) o;
System.out.println(entry); //key=value
System.out.println(entry.getKey() + " / " + entry.getValue());
}
2.AbstractMap
定义
public abstract class AbstractMap
//获取所有键值对,需要子类实现,AbstarctMap 中唯一的抽象方法
public abstract Set<Entry<K,V>> entrySet();
AbstractMap成员变量
transient volatile Set<K> keySet = null;
transient volatile Collection<V> values = null;
keySet保存map中所有的键,values保存所有的值。使用transient volatile 表示不可序列化,并发环境修改变量会保证线程可见性
具体函数实现
获取:
public V get(Object key) {//很多实现类重写了该方法;时间复杂度O(n)
//获取保存Map.Entry集合的迭代器
Iterator<Entry<K,V>> i = entrySet().iterator();
if (key==null) {//查询分为null和非null
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)//存在Key为null的数据
return e.getValue();
}
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return e.getValue();
}
}
return null;
}
添加:
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
默认是不支持添加操作,所以如果要实现不可变的Map,只需要继承这个类重写entrySet()方法;如果要实现可变的类,需要重写put(key,value)方法
删除:
public V remove(Object key) {
Iterator<Entry<K,V>> i = entrySet().iterator();
Entry<K,V> correctEntry = null;//用于记录要删除的Entry<K,V>数据
if (key==null) {
while (correctEntry==null && i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
correctEntry = e;
}
} else {
while (correctEntry==null && i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
correctEntry = e;
}
}
V oldValue = null;
if (correctEntry !=null) {
oldValue = correctEntry.getValue();//从Entry<K,V>获取value
i.remove();
}
return oldValue;
}
查询某Key或者某value是否存在
public boolean containsValue(Object value) {//O(n),
Iterator<Entry<K,V>> i = entrySet().iterator();
if (value==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getValue()==null)
return true;
}
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (value.equals(e.getValue()))
return true;
}
}
return false;
}
public boolean containsKey(Object key) {
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
return true;
}
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return true;
}
}
return false;
}
查询size
public int size() {
return entrySet().size();//查set<Entry<K,V>>的size
}
public boolean isEmpty() {
return size() == 0;
}
equals()和hashcode()
public boolean equals(Object o) {//判断指定对象是否和当前map一致
if (o == this)
return true;
if (!(o instanceof Map))
return false;
Map<K,V> m = (Map<K,V>) o;
if (m.size() != size())
return false;
try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {//根据Entry<K,V>的value是否为null划分两种情况
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
public int hashCode() {//整个Map的hashCode,求和
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
获得所有键
public Set<K> keySet() {
if (keySet == null) {//如果keySet为空,则创建一个空的AbstractSet
keySet = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();//Set<Entry<K,V>>.iterator()
public boolean hasNext() {
return i.hasNext();
}
public K next() {
return i.next().getKey();
}
public void remove() {
i.remove();
}
};
}
public int size() {
return AbstractMap.this.size();
}
public boolean isEmpty() {
return AbstractMap.this.isEmpty();
}
public void clear() {
AbstractMap.this.clear();
}
public boolean contains(Object k) {
return AbstractMap.this.containsKey(k);
}
};
}
return keySet;
}
获得所有值
public Collection<V> values() {
if (values == null) {
values = new AbstractCollection<V>() {
public Iterator<V> iterator() {
return new Iterator<V>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public V next() {
return i.next().getValue();
}
public void remove() {
i.remove();
}
};
}
public int size() {
return AbstractMap.this.size();
}
public boolean isEmpty() {
return AbstractMap.this.isEmpty();
}
public void clear() {
AbstractMap.this.clear();
}
public boolean contains(Object v) {
return AbstractMap.this.containsValue(v);
}
};
}
return values;
}
Map接口中有个Map.Entry,AbstractMap中有两个Entry,分别是
public static class SimpleEntry<K,V> implements Entry<K,V>, java.io.Serializable //可变的键值对
private final K key; private V value;
public static class SimpleImmutableEntry<K,V> implements Entry<K,V>, java.io.Serializable //不可变的键值对
private final K key; private final V value;
这两个内部类程序另一个区别是:SimpleImmutableEntry的setValue方法回抛UnsupportedOperationException,而另一个可以赋值。
public static class SimpleImmutableEntry<K,V>
implements Entry<K,V>, java.io.Serializable
{
private static final long serialVersionUID = 7138329143949025153L;
private final K key;
private final V value;
public SimpleImmutableEntry(K key, V value) {
this.key = key;
this.value = value;
}
public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
this.key = entry.getKey();
this.value = entry.getValue();
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(V value) {
throw new UnsupportedOperationException();
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
return eq(key, e.getKey()) && eq(value, e.getValue());//eq()是AbstractMap里的方法
}
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
public String toString() {
return key + "=" + value;
}
}
AbstractMap里的eq()
private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
3.HashMap:
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。(拉链式)
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
HashMap实现Map接口,继承AbstractMap
HashMap数据结构只需要经过哈希运算,能得到目标元素在哈希表中的位置,然后通过比较相同位置元素,就能得到数据,所以该结构查找效率高。
HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。
HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。
容量是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
加载因子太大会导致冲突的可能性大,查找效率变低。太小了频繁扩容,重新哈希,性能降低。
当HashMap中的元素越来越多的时候,hash冲突的几率也就越来越高,因为数组的长度是固定的。所以为了提高查询的效率,就要对HashMap的数组进行扩容,数组扩容这个操作也会出现在ArrayList中,这是一个常用的操作,而在HashMap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize。
那么HashMap什么时候进行扩容呢?
当HashMap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //默认初始容量 16;必须是2^n
static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量2^30
static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认加载因子0.75
static final Entry<?,?>[] EMPTY_TABLE = {};//当数组还没有进行扩容操作时候共享的一个空表对象
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; //链表数组
transient int size; //键值对数量
int threshold; //阈值,下次需要扩充时的值,用于判断是否需要扩容 = 容量*加载因子
final float loadFactor; //哈希表的加载因子
transient int modCount; //hashMap每次修改,会+1,为了保证快速失败机制(fail-fast)
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
transient int hashSeed = 0;//用于计算Key的hash值,它与key的hashCode进行按位异或运算。这个hashSeed是一个与实例相关的随机值,主要用于解决hash冲突
构造方法:
//设置容量和加载因子
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +loadFactor);
this.loadFactor = loadFactor;
threshold = initialCapacity;
init();
}
//指定容量,默认加载因子
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
//使用默认初始容量和加载因子创建哈希表
public HashMap() {
this(DEFAULT_INITIAL_CAPACITY,DEFAULT_LOAD_FACTOR);
}
//创建m的哈希表
public HashMap(Map<? extends K, ? extends V> m) {
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
inflateTable(threshold);//扩容
// 将m中的全部元素逐个添加到HashMap中
putAllForCreate(m);
}
private void inflateTable(int toSize) {
int capacity = roundUpToPowerOf2(toSize);//判断值是否大于最大值,大于则设置该值为最大值;否则计算出大于toSize最临近的2的N此方的值
//这里展示了 阈值 = 数组大小 * 加载因子
threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
table = new Entry[capacity];//
initHashSeedAsNeeded(capacity);
}
//初始化hashSeed
final boolean initHashSeedAsNeeded(int capacity) {
boolean currentAltHashing = hashSeed != 0;
boolean useAltHashing = sun.misc.VM.isBooted() &&
(capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean switching = currentAltHashing ^ useAltHashing;
if (switching) {
hashSeed = useAltHashing
? sun.misc.Hashing.randomHashSeed(this)
: 0;
}
return switching;
}
第二种构造函数,向HashMap添加元素的方法
private void putAllForCreate(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
putForCreate(e.getKey(), e.getValue());
}
private void putForCreate(K key, V value) {
int hash = null == key ? 0 : hash(key);
int i = indexFor(hash, table.length);//得到数组位置
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
e.value = value;
return;
}
}
createEntry(hash, key, value, i);
}
//新添Entry
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
链表节点:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;//每组数据的键
V value;//值
Entry<K,V> next;//它指向的下一个节点指针
int hash;//哈希值,意思是在表中的位置
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
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 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public final int hashCode() {
return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
}
public final String toString() {
return getKey() + "=" + getValue();
}
void recordAccess(HashMap<K,V> m) {
}
void recordRemoval(HashMap<K,V> m) {
}
}
扩容:
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity));//原先数据赋值给新建的Entry[]
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {//table是HashMap存储的数组
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {//是否需要重新计算hash
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
添加:
public V put(K key, V value) {
if (table == EMPTY_TABLE) {//如果没有初始化
inflateTable(threshold);//初始化hashmap 包括创建hashMap保存的元素的数组等
}
if (key == null)//Key为null时放在0位置
return putForNullKey(value);
int hash = hash(key);//使用Key计算hash值
int i = indexFor(hash, table.length);//使用hash值和数组长度计算在Entry[]中的位置
for (Entry<K,V> e = table[i]; e != null; e = e.next) {//遍历table[i]位置的链表
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//如果Key存在在Hashmap中,会代替原先value值
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);//,如果Key不存在hashmap中,则添加到Map方法中
return null;
}
indexFor计算Entry[]中的存储位置:
static int indexFor(int h, int length) {
// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
return h & (length-1);
}
:
addEntry:
void addEntry(int hash, K key, V value, int bucketIndex) { //bucketIndex Entry[]数组的索引
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length); //扩容,数据重新计算位置放入hashMap
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
//添加到HashMap
createEntry(hash, key, value, bucketIndex);
}
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);//将新添加的Entry的next元素指向table[bucketIndex]第一个元素;也就是新添加的放在链头
size++;
}
获取:
public V get(Object key) {
if (key == null) //key为null返回table[0]中key为null的值
return getForNullKey();
Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
final Entry<K,V> getEntry(Object key) {//根据key获取对应的Entry[]
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)]; //遍历该位置单链表,根据Key判断
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
移除:
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
final Entry<K,V> removeEntryForKey(Object key) {//先根据hash获取位置table[i],然后遍历单链表获取
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;
while (e != null) { //prev->e->next
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)//如果是table[i]的第一个元素,则把该单链表第二个元素提为第一
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
HashIterator:
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // 下一个Entry
int expectedModCount; // 快速失败机制使用,每次使用Iterator时都会判断该值是否与modCount比较是否相等,不等说明其他线程修改了该HashMap就会fail-fast
int index; // 当前位置索引
Entry<K,V> current; // 当前位置Entry数据
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)//在构造器会找到数组中第一个不是指向null的那个元素,将这个元素存入next中,同时index指向这个 数组元素的下一个下标
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {//如果到达链表(桶)的结尾
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)//找到table数组中下一个不是指向空”链表“的那个元素,使next更新为”链表“首结点,同时更新index
;
}
current = e;
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
Serializable序列化方法
// 将HashMap的“总的容量,实际容量,所有的Entry”都写入到输出流中
private void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
s.defaultWriteObject();
if (table==EMPTY_TABLE) {
s.writeInt(roundUpToPowerOf2(threshold));
} else {
s.writeInt(table.length);
}
s.writeInt(size);
if (size > 0) {
for(Map.Entry<K,V> e : entrySet0()) {
s.writeObject(e.getKey());
s.writeObject(e.getValue());
}
}
}
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
throw new InvalidObjectException("Illegal load factor: " +loadFactor);
}
table = (Entry<K,V>[]) EMPTY_TABLE;
// Read in number of buckets
s.readInt(); // ignored.
int mappings = s.readInt();
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " + mappings);
int capacity = (int) Math.min(
mappings * Math.min(1 / loadFactor, 4.0f),HashMap.MAXIMUM_CAPACITY);
// allocate the bucket array;
if (mappings > 0) {
inflateTable(capacity);
} else {
threshold = capacity;
}
init(); // Give subclass a chance to do its thing.
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
putForCreate(key, value);//创建entry放入数组
}
}
keySet(),values(),和entrySet()是怎么实现的呢?
其实三个实现迭代器迭代都是依据HashIterator。
首先看keySet()方法
public Set<K> keySet() {
Set<K> ks = keySet;
//如果为空则new一个KeySet
return (ks != null ? ks : (keySet = new KeySet()));
}
KeySet在HashMap中私有。
private final class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return HashMap.this.removeEntryForKey(o) != null;
}
public void clear() {
HashMap.this.clear();
}
}
在私有类KeySet的Iterator()方法中返回一个new KeyIterator。
在另外两个values,EntrySet类中,和KeySet区别也只是iterator()返回的迭代器不同。
Iterator<K> newKeyIterator() {
return new KeyIterator();
}
private final class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}
该迭代器继承HashIterator,只实现next()方法,说明该类的数据也就是用的HashIterator。
另外两个迭代器:
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}
private final class ValueIterator extends HashIterator<V> {
public V next() {
return nextEntry().value;
}
}
keySet和values和entrySet本质既然一样,就可以通过封装其相同的部分(也就是这里的HashIterator),再各自实现最重要的next方法。
nextEntry()方法是HashIterator中的final方法,用于返回Entry。
然后keySet和values的迭代器分别从中获取key和value。
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
可见,对于迭代器的操作,其实都是根据底层的table来实现的,也就是直接操作键值对。在得到Entry之后再获得它的key或者value。正因为如此,迭代器的底层直接根据table进行操作,所以如果有别的容器持有了这个迭代器内部类,就可以直接实现同步中的可见性:对HashMap的改变体现在table,而传递出去的内部类可以访问table。
HashMap遍历
(1)
Map<String, String> map = new HashMap<String, String>();
for (Entry<String, String> entry : map.entrySet()) {
entry.getKey();
entry.getValue();
}
(2)
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
entry.getKey();
entry.getValue();
}
(3)
Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
map.get(key);
}
HashMap的线程是不安全的,可以使用如下变成线程安全的Map
Map m = Collections.synchronizedMap(new HashMap(…));
多线程环境中推荐是ConcurrentHashMap
Thanks:
http://blog.youkuaiyun.com/u011240877/article/details/68939826
http://www.cnblogs.com/skywang12345/p/3310835.html
http://www.cnblogs.com/dsj2016/p/5551059.html
http://blog.youkuaiyun.com/liubin119712/article/details/51052283