与Collection接口那条主线一样,Map接口时Java集合框架里的另一条主线。Map描述的是键(key)值(value)对的映射,类似于一本英汉词典:key是英文单词,value是汉语意思,其中key不允许重复,value可以(词典中的单词不能重复,但是汉语意思可以重复,例如go和leave都有离开的意思)。与Collection接口一样,Map接口也定义了它的一些规范,下面我们来看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);
void clear();
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
boolean equals(Object o);
int hashCode();
}
接口的方法的作用和方法名一样,比较好理解。其中有两个方法返回类型是Set类型,Set类型相当于数学上的集合,它与Collection最主要的区别就是Set不允许有重复的元素,我们来看看Set接口的定义:
public interface Set<E> extends Collection<E> {
}
是的,什么也没有!可能有些版本的源码把Collection接口内定义的方法写到了Set集合里面,如果去掉Collection接口内的方法,Set接口就是上面这样。但是Set接口要求实现者保证集合类没有重复的元素。
Entry表示一个条目(一组key,value)是Map接口的一个内部接口,定义如下:
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
}
方法的作用和名字的含义一样。
与Collection与AbstractCollection关系一样,这边也有一个AbstractMap的抽象类提供了Map接口的默认实现,下面我们来看一下其默认实现代码:
public abstract class AbstractMap<K,V> implements Map<K,V> {
// 唯一的构造函数
protected AbstractMap() {
}
// entrySet是一个Set类型,Set继承自Collection接口,调用Collection的size方法
public int size() {
return entrySet().size();
}
// 判断是否为空
public boolean isEmpty() {
return size() == 0;
}
// Map 接口的方法,是否包含某个具体的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;
}
// Map 接口定义的方法
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;
}
// Map 接口定义的方法
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;
}
// 默认实现,不支持此操作
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
// 通过迭代器来实现
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 函数
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
// 清空 从这里就可以看出,默认实现的entrySet() 返回的是视图,而不是一份拷贝
public void clear() {
entrySet().clear();
}
transient volatile Set<K> keySet = null;
transient volatile Collection<V> values = null;
// 默认keySet的实现,可以看出没有重新拷贝一份key。这里用到了匿名内部类
public Set<K> keySet() {
if (keySet == null) {
keySet = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
private Iterator<Entry<K,V>> i = entrySet().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;
}
// values 的默认实现
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;
}
// 抽象方法,需要子类实现
public abstract Set<Entry<K,V>> entrySet();
// 重载Object类的方法
public boolean equals(Object o) {
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) {
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;
}
// 默认Hash的实现就是所有元素hash值相加
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
// 重载Object的方法
public String toString() {
Iterator<Entry<K,V>> i = entrySet().iterator();
if (! i.hasNext())
return "{}";
StringBuilder sb = new StringBuilder();
sb.append('{');
for (;;) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
sb.append(key == this ? "(this Map)" : key);
sb.append('=');
sb.append(value == this ? "(this Map)" : value);
if (! i.hasNext())
return sb.append('}').toString();
sb.append(',').append(' ');
}
}
}
AbstractMap内还有两个静态内部类提供了Map接口中Entry接口的默认实现,分别是SimpleEntry与SimpleImmutableEntry,方法比较简单,就不赘述了。这两个类之间的区别就是后者的属性都使用了final修饰,是不可变类。