Map的值的存储方式与Collection的存储方式稍有不同,Map中是键值对存储,键唯一,值可以重复。Map的实现类有HashMap、WeakHashMap、Hashtable和TreeMap。本篇文章介绍除HashMap外的Map,由于HashMap的内容较多,因此将其单独放在这篇文章。
Map
Map与Collection无关,他们的存储值的方式也完全不同,只是在实现某些数据结构的时候可能会互相依赖。主要方法如下:
//键值对数量
int size();
//键值对数量是否为0
boolean isEmpty();
//是否包含指定键
boolean containsKey(Object key)
//是否包含指定值
boolean containsValue(Object value)
//根据键获取值
V get(Object key)
//向Map中添加键值对并返回值
V put(K key,V value)
//通过键删除键值对并返回值
V remove(Object key)
//清空Map
void clear();
//返回所有的键,存储在Set中
Set<K> keySet();
//返回所有的值,存储在Collection<V>中
Collection<V> values();
//内部接口,Map依靠此接口实现键值对存储
interface Entry<K,V> {
//获取键
K getKey();
//获取值
V getValue();
//设置值
V setValue(V value);
}
AbstractMap
在讨论Map的具体实现类之前,我们先讨论一下AbstractMap类,这个类的作用提供Map中一些方法的通用实现,是所有Map的父类。
//键值对的个数
public int size(){
return entrySet().size();
}
//返回Entry<K,V>的Set表示,由子类实现
public abstract Set<Entry<K,V>> entrySet();
//是否为空Map
public boolean isEmpty(){
return size() == 0;
}
//Map中是否包含指定的Value,这个方法与Collection中的实现一样,当然其实就是Set的方法,只不过封装的是Entry<K,V>
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中是否包含指定的key,与containsValue()方法实现完全相同
public boolean containsKey(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 true;
}
}
} else {
while(i.hasNext()){
Entry<K,V> e = i.next();
if(key.equals(e.getKey())){
return true;
}
}
}
return false;
}
//通过指定的key返回对应的value,没有则返回null。此方法与containsKey()类似,只是返回值不同
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 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;
}
//返回key的Set集合,keySet为AbstractMap中的属性,子类如果没有定义keySet的值,此方法用匿名内部类定义了AbstractSet的子类和Iterator的实现类来自定义对key的遍历。
public Set<K> keySet(){
Set<K> ks = keySet;
if(ks == null){
ks = new AbstractSet<K>(){
public Iterator<K> iterator(){
return new Iterator<K>(){
private Iterator<K> i = entrySet().iterator();
public boolean hasNext(){
return i.hasNext();
}
public K next(){
return i.next().getKey();
}
public void remove(){
return 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 key){
return AbstractMap.this.containsKey(key);
}
};
keySet = ks;
}
return ks;
}
//返回value的Collection集合,values为AbstractMap类的属性,与keySet作用相同,实现方式也相同
public Collection<V> values(){
collection<V> vals = values;
if(vals == null){
vals = new Collection<V>(){
public Iterator<V> iterator(){
return new Iterator<V>(){
private Iterator<V> i = entrySet().iterator();
public boolean hasNext(){
return i.hasNext();
}
public V next(){
return i.next().getValue();
}
public void remove(){
return 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;
}
TreeMap
TreeMap是一个有序的键值对集合,基于红黑树实现,
WeakHashMap
WeakHashMap相比于其他的Map实现类较少用甚至较少见到,WeakHashMap的特点是键是弱引用。
HashTable
HashTable与HashMap功能和结构类似,但也有一些区别,如下:
- HashTable是线程安全的,它的的方法都使用了synchronized修饰;HashMap不是线程安全的。
- HashTable的键和值都不能为null;HashMap键和值都可以是null,且值可以有多个null。
- HashTable继承的是Dictionary类(已过时),HashMap继承的是AbstractMap类。