1.继承关系
HashMap是继承AbstractMap抽象类,实现了Map接口,接下来先分析这几个父类:
1.1 Map<K,V>
map是key=value这种存储数据格式的接口,他定义了map的基本操作方法,以及存储的数据格式 Entry<k,V>
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);
void clear();
//获取所有的键值对中的key,返回set
Set<K> keySet();
//获取所有的value,返回到Collection
Collection<V> values();
//注意这三个的方法,上面单个获取key或者value都是调用这个方法,这个将在
//以后的类介绍。
Set<Map.Entry<K, V>> entrySet();
//同时,接口中也定义了map存储的元素类型为Entry
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
}
}
1.2 AbstractMap<K,V>
这个抽象类是对Map接口做一个基本的实现,实现一些通用的功能,避免子类重复实现,其中有一些设计地方
需要思考下:
public abstract class AbstractMap<K,V> implements Map<K,V> {
//获取map中的数据,并将以Set<Entry<K,V>>形式返回,实现由子类,只需要记住功能
public abstract Set<Entry<K,V>> entrySet();
//获取map中存入的数量,实现方式是通过调用entrySet()方法,返回的类型是Set集合,
//通过Set属性来操作数据,具体的实现是在 entrySet()方法中,这个在hashmap中讲解。
public int size() {
return entrySet().size();
}
public boolean isEmpty() {
return size() == 0;
}
//判断map中是否存在指定key的值,可以看到,实现方式是获取到map中元素的Set,然后循环遍历
//可知道时间复杂度是o(n),HashMap对这个进行了覆盖,是复杂度在不碰撞的情况下为o(1)
public boolean containsKey(Object key) {
//同样是通过这个方法,获取map中数据的set集合,进行每项循环
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
//因为map支持存储null作为key值,所以需要分开判断,如果key为空,判断条件应该是null=e.key
if (key==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
return true;
}
} else {
//同样,当key不等于null时,判断条件就应该是key.equals(e.key)
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return true;
}
}
return false;
}
//判断map中是否存在指定value的值,也是遍历map元素的set集合,HashSet虽然对这个进行了重写,但是
//时间复杂度相差不大,因为HashMap中存储的key是可以计算出来的,但是value是杂乱的,只能通过遍历
public boolean containsValue(Object value) {
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;
}
//获取key对应的value值
public V get(Object key) {
Iterator<Entry<K,V>> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
return e.getValue();
}
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return e.getValue();
}
}
return null;
}
//存放key,依赖具体的子类实现
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
//移除元素,根据key值,可以看到这个的实现是使用迭代器的remove函数,但是hashmap不是,
//他重写了方法,并且在HashMap返回的entrySet()的Set集合,remove方法也被重写,是调用HashMap自身方法
public V remove(Object key) {
Iterator<Entry<K,V>> i = entrySet().iterator();
Entry<K,V> correctEntry = null;
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();
i.remove();
}
return oldValue;
}
//调用put方法,去实现复制一个map集合
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
public void clear() {
entrySet().clear();
}
//返回一个keyset的集合,可以看一下实现方式,返回的是一个抽象的Set对象,在里面
//实现了他的迭代其中的方法,迭代器方法的实现也是依赖entrySet(),这个调用EntrySet()
//获取到Set集合,然后获取Entry集合的Iterator,外部调用key的迭代器遍历时,其实内部就是在
//调用enTrySet的迭代器,就是改写了下next()的返回值。
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
//获得map的元素组成的set集合的迭代器
private Iterator<Entry<K,V>> i = entrySet().iterator();
//直接就是调用的entrySet()的迭代器方法
public boolean hasNext() {
return i.hasNext();
}
public K next() {
//唯一不同之处
return i.next().getKey();
}
public void remove() {
i.remove();
}
};
}
/*********************对set集合的一些简单实现*************************/
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);
}
};
keySet = ks;
}
return ks;
}
//和keySet()一样的思路
public Collection<V> values() {
Collection<V> vals = values;
if (vals == null) {
vals = 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);
}
};
values = vals;
}
return vals;
}
//比较方法,可以看到是比较对象,之后比较每个元素是否相同
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Map))
return false;
Map<?,?> m = (Map<?,?>) 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) {
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;
}
}
通过分析得知,在抽象map中,最重要的方法时entrySet(),他是很多方法的被调用者,比如keySet(),values(),
continusKey()等,所以子类的实现这个抽象方法,并返回了Set对象,这个设计必须思考。
可以看keySet()方法,他的实现不是将从entrySet()中获取到所有Entry,取出来key存入到自己new出来的
set中,而是自己创建一个匿名的set对象,将对对象的获取通过调用entrySet()方法获取,实现更加机巧。
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
//
.......迭代器实现
//
}
//
.......set抽象方法实现
//
}
}
这个set使用的方法也就是迭代key,所以这种实现方式返回一个set,就相当于自定义了一个set,里面的数据结构
和实现方式由自己重写,对set元素的存储不是定义一个数组或者数结构,而是让entrySet()决定,这个只负责调用就行。
上面的分析应该放在hashMap中entrySet()方法来说的,提前说,了解一下思想:
1.3 HashMap<K,V>
这里介绍HashMap与父类直接的关系,他们直接怎么设计相互调用的,具体的Hash存取值,在下一篇博客,
这个是从总体上理解HashMap的结构,为简化HashMap使用链式解决碰撞,这里简单提一下实现。
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
//HashMap中存储的节点时Node
static class Node<K,V> implements Map.Entry<K,V> {
//hash设置为final,表示节点的hash值存储后是不可变的,否则找不到元素
//因为hash的值是根据key的hashcode算出来,如果key值改变,则hash计算和存储的
//数据就不一样,所以key值声明为不可变,hash同样不可变
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;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
/******************--method--*************************/
//构造方法,指定加载因子,初始容量
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;
this.threshold = tableSizeFor(initialCapacity);
}
//获取指定key元素值
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
//当存放节点的数组table不为空时(buckets桶)
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
//直接在数组中命中
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
//如果是TreeNode节点,则在红黑树中查找
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
//否则在链表中查找
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
//存放数据
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
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;
//size表示map中的个数
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
//扩展map容量
final Node<K,V>[] resize() {
//******
}
/**
* 做一下分析,上面的代码简单的说了一下的hashMap是如何存取值,实现当时是使用hash散列存储,
* 解决碰撞冲突的方法时使用链地址法。查看下面几个方法,重写或者实现了父类的方法。
*/
/*
*这是一个唯一没有被实现的方法,HashMap的实现是先判断是否已经存在EntrySet对象,不存在则
*创建一个新的。EntrySet是一个静态内部类
*/
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
//查看EntrySet的实现,是不是和上面说的KeySet的实现方式是一模一样的,只是数据源上次的是
//调用entrySet()的方法去获取,这个是调用hashmap的方法去实现。
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
// AbstractMap 中的方法 return entrySet().size();
public final int size() { return size; }
// AbstractMap 中的方法 就是清空enteySet返回的set集合
public final void clear() { HashMap.this.clear(); }
//下面重点讲解
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
//通过调用getNode()方法实现了检测Set中是否存在元素,类似以重新创建了一个新的Set子类。
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
//remove通过调用hashmap的remove方法。
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
/* public final Spliterator<Map.Entry<K,V>> spliterator() {
return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}*/
}
}
上面的分析中,我们已经能够看到了一些AbstractMap的基本实现方式,子类必须实现定义的抽象方法,父类
依靠这些由子类具体实现的方法,完成操作。
下面看一下对于AbstractMap中的containsKey如何实现的:
public boolean containsKey(Object key) {
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
if (key==null) {
// ...
} else {
// ....
}
return false;
}
通过代码很明显就是通过调用子类实现的entrySet(),返回一个Set,调用迭代器方法,去遍历里面的数据,
去检测数据。仔细想一下,我们学习了HashMap的entrySet() 方法,知道实现是创建匿名Set,创建了一个新的
set对象,但是这个对象中,只有一些size()等方式,却没有迭代器,所以肯定要创建迭代器方法。在想一下,
hashmap的存储是Hash散列表,迭代器是顺序遍历所有元素,肯定涉及到HashMap的遍历,看一下实现:
同样还在HashMap类中,在entrySet方法中创建的自定义EntrySet类中,对Iterator的返回:
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
//就是创建迭代器对象
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
}
//HashMap中的内部类,实现了Iterator泛型是Entry(重要),继承了HashIterator
//只实现了next接口,返回当前迭代到的元素是Entry,试下关键还在于HashIterator
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() {
return nextNode();
}
}
//是抽象内部类,是Iterator的通用实现,为什么说通用,因为需要迭代的有三个,分别是KeySet返回K的迭代器
//values返回V的迭代器,还有一个entrySet返回一个Entry<K,V>的迭代器,而这三个的元素获取,有无元素是
//一样的。
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot 表示tab的下标
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
//创建时,寻找到数组中第一个元素
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
//下一个节点元素就是,如果是
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)//fast - fali
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
//链表中存在下一个节点不
if ((next = (current = e).next) == null && (t = table) != null) {
//一直循环,知道数组末尾
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
可以看出在内部类EntrySet实现了Iterator接口,内部自定义实现了迭代器获取元素。有这种需要的方法还有:
//获取keySet的集合
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
//获取valueSet的集合
public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new Values();
values = vs;
}
return vs;
}
/*******创建的内部类***********/
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
}
final class Values extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<V> iterator() { return new ValueIterator(); }
public final boolean contains(Object o) { return containsValue(o); }
public final Spliterator<V> spliterator() {
return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super V> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
/**********************辅助实现的迭代器**********************/
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
将上面的三个放在一起比较,比较容易看出来结构的设计;
看一下HashMap对一些方法的覆盖:
//判定是否包含指定key,通过hash取值,复杂度o(1)
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
//置空数组,不是迭代entySet()的Set集合了
public void clear() {
Node<K,V>[] tab;
modCount++;
//将所有的数组置为空
if ((tab = table) != null && size > 0) {
size = 0;
for (int i = 0; i < tab.length; ++i)
tab[i] = null;
}
}
//是否包含指定value值,直接遍历table数组,省去AbstractMap中通过entrySet()方法获取
//自定义的EntrySet对象,然后获取迭代器,在进行下面的算法遍历,减去了方法之间的调用。
public boolean containsValue(Object value) {
Node<K,V>[] tab; V v;
if ((tab = table) != null && size > 0) {
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next) {
if ((v = e.value) == value ||
(value != null && value.equals(v)))
return true;
}
}
}
return false;
}
最后的最后,整理下HashMap的类结构:
Node map存储的元素类型,继承Map.Entry
KeySet 自定义内部类,实现Set接口,用于存储key值集合
Values 自定义内部类,实现Set接口,用于存储value值集合
EntrySet 自定义内部类,实现Set接口,用于存储EntrySet值集合
HashIterator 抽象类迭代器,定义迭代器的通用实现
KeyIterator key的迭代器
ValueIterator value的迭代器
EntryIterator EntryIterator迭代器
HashMapSpliterator
KeySpliterator
ValueSpliterator
EntrySpliterator
TreeNode