[集合类] 源码解析9(Map接口和AbstractMap抽象类)

上一篇:[集合类] 源码解析8(PriorityQueue类)

1. Map接口

我们首先看一下Map接口的定义,按照惯例,翻译一下注释。

/**
 * Map是一个将key(键)映射到value(值)的对象。Map不能包含重复的key,每个key最多可以映射到一个value。
 *
 * 这个接口代替了Dictionary类, Dictionary类是一个完全抽象类,而不是接口。
 *
 * Map接口提供了三个集合视图, 他们允许将Map的内容视为 
 * key的set集合,value的collection集合,key-value的set集合
 * 映射的顺序定义为映射集合视图上的迭代器返回其元素的顺序。
 * 一些Map的实现,例如TreeMap,对他们的顺序做了特定的保证,其他的类,例如HashMap,则没有。
 *
 * 注意:要格外小心使用可变对象作为key
 * 如果使用equals比较的方式改变了一个对象的值,而对象是Map的一个key,则不规定Map的行为(没太懂啥意思。。)
 * 这种禁止的一种特殊情况是,不允许Map将自己作为key。
 * 虽然map可以将自己作为value,但是要特别小心:equals和hashCode方法在这样的map上将不能被很好的定义。
 *
 * 所有的map实现类都应该提供两个“标准”构造函数:
 * 一个空参构造函数,创建一个空的映射
 * 另一个有一个Map类型的单一参数,创建一个新的,和参数同样的key-value映射的Map
 * 事实上,后一个构造函数允许用户复制任何Map,生成所需的Map。
 * 没有办法强制执行这个建议(因为接口不能包含构造函数),但是JDK中的所有通用Map实现都遵守这个建议。
 *
 * 此接口中的“破坏性”方法(即修改Map的方法)在该Map不支持操作时抛出UnsupportedOperationException。
 * 如果是这种情况,调用对Map没有影响,这些方法可能会抛出UnsupportedOperationException。
 * 例如,在不可修改的Map上调用putAll(Map)方法时,如果要“叠加”(添加)的Map为空,可能会抛出异常。
 *
 * 一些Map实现对它们可能包含的key和value有限制。例如,有些实现禁止key和value为空,有些实现限制key的类型。
 * 试图插入不符合条件的key或value会引发未检查异常,通常是NullPointerException或ClassCastException。
 * 试图查询不符合条件的key或value是否存在可能会引发异常,或者只返回false。
 * 更概括地说,尝试对不符合条件的key或value进行操作,操作完成不会将不符合条件的元素插入到Map中
 * 这可能会引发异常,也可能会成功(取决于实现的选项)。此类异常在此接口的规范中被标记为“可选”。
 *
 * 集合框架接口中的许多方法都是根据equals方法定义的。
 * 例如,containsKey(Object key)方法的规范说:
 * “当且仅当此Map包含键k的映射(key==null ? k==null:key.equals(k))。”
 * 本规范不应被解释为调用Map.containsKey,传入非空参数key会导致key.equals(k)被任意键k调用。
 * 实现可以自由地实现优化,从而避免了equals调用,
 * 例如,首先比较两个键的哈希码。(Object.hashCode()规范保证两个哈希码不相等的对象不能相等。)
 * 更一般地说,各种集合框架接口的实现可以在实现者认为合适的地方自由地利用底层Object方法的指定行为。
 *
 * 一些执行Map递归遍历的操作可能会失败,由于Map直接或间接包含自身实例的异常。
 * 这包括clone()、equals()、hashCode()和toString()方法。
 * 实现可以有选择地处理自引用场景,但是大多数当前的实现并不这样做。
 *
 * 该接口是Java集合框架的成员。
 */
public interface Map<K,V> {

1) Entry接口

Entry接口是Map接口的字接口,他抽象了数据存储的节点,定义了一些操作数据的基本方法。

/**
 * 一个Map的项(键值对)Map.entrySet方法返回一个Map的集合视图,其元素就是这个类。
 * 获取Map entry引用的方法来自这个集合视图的迭代器。
 * 这些Map.Entry对象只在迭代期间有效
 * 更正式的说法是,如果在迭代器返回entry之后对更改了map,则map entry的行为没有定义
 * 除非通过setValue方法操作map entry。
 */
interface Entry<K,V> {
    /**
     * 返回与此项对应的键
     * @throws IllegalStateException 如果entry被移除,实现可能抛出这个异常
     */
    K getKey();

    /**
     * 返回与此项对应的值。如果映射已经从map中删除(被迭代器的remove操作),则此调用结果是未定义的。
     * @throws IllegalStateException 如果entry被移除,实现可能抛出这个异常
     */
    V getValue();

    /**
     * 用特定的value替换这个entry对应的value。
     * (写进map。)如果映射已经从map删除(被迭代器的remove操作),则这个调用的行为未定义。
     * 返回旧的value
     * @throws UnsupportedOperationException 如果map不支持put操作
     * @throws ClassCastException 如果特定值的类阻止其存储到map中
     * @throws NullPointerException 如果map不允许value为null,而特定value为null
     * @throws IllegalArgumentException 如果value的某些属性阻止将其存储在map中
     * @throws IllegalStateException 如果entry被移除,实现可能抛出这个异常
     */
    V setValue(V value);

    /**
     * 将指定的对象与此entry进行相等性比较。
		 * 如果给定的对象也是一个map entry,且两个entry表示相同的映射,则返回true。
		 * 更正式的说,两个entry e1 和 e2 表示相同的map,如果:
     *     (e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey()))
     * 		 &&
     *     (e1.getValue()==null ? e2.getValue()==null : e1.getValue().equals(e2.getValue()))
     * 这将确保equals方法在Map.Entry接口的不同实现之间正常工作。
     */
    boolean equals(Object o);

    /**
     * 返回map entry的hashCode。map entry的hashCode定义如下: 
     *     (e.getKey()==null ? 0 : e.getKey().hashCode()) 
     *     ^
     *     (e.getValue()==null ? 0 : e.getValue().hashCode())
     * 这将确保对于任意两个entry e1和e2,如果e1.equals(e2)则e1.hashCode()==e2.hashCode()
     * 这是Object.hashCode的一般约定要求的。
     */
    int hashCode();

2) 方法

/**
 * 返回此映射中的键值映射的数目。
 * 如果映射包含大于Integer.MAX_VALUE元素,返回Integer.MAX_VALUE。
 */
int size();

/**
 * 如果map不包含key-value映射,返回true
 */
boolean isEmpty();

/**
 * 如果此映射包含指定键的映射,则返回true。
 * 更正式地说,当且仅当此map包含一个key k,使得(key==null ? k == null: key.equals(k)),返回true
 *
 * @throws ClassCastException 如果键的类型不适合此Map
 * @throws NullPointerException 如果指定的key为null,并且此Map不允许key为null
 */
boolean containsKey(Object key);

/**
 * 如果此Map将一个或多个key映射到指定的value,则返回true。
 * 更正式地说,当且仅当此Map包含至少一个到值v的映射
 * 使得(value==null ? v == null: value.equals (v)) 则返回true。
 * 对于Map接口的大多数实现,此操作可能需要线性时间。
 *
 * @throws ClassCastException 如果value的类型不适合此Map
 * @throws NullPointerException 如果指定的value为null,并且此Map不允许null
 */
boolean containsValue(Object value);

/**
 * 返回指定key映射到的value,如果此Map不包含key的映射,则返回null。
 *
 * 更正式地说,如果这个Map包含一个从key k到value v的映射,
 * 使得(key==null ? k==null: key.equals(k)),则该方法返回v;
 * 否则返回null。(最多可以有一个这样的映射。)
 *
 * 如果此Map允许空值,则null的返回值不一定表示该映射不包含键的映射;
 * 也有可能映射显式地将键映射到null。
 * 可以使用containsKey操作来区分这两种情况。
 *
 * @throws ClassCastException 如果value的类型不适合此Map
 * @throws NullPointerException 如果指定的key为null,并且此Map不允许null
 */
V get(Object key);

// Modification Operations 修改操作

/**
 * 将指定value与此Map中的指定key关联(可选操作)。
 * 如果Map以前包含key的映射,则旧值将被指定的value替换
 * (当且仅当m.containsKey(k)返回true时,一个map m才被认为包含了一个key k的映射。)
 *
 * @return 返回前一个与key关联的值,或者如果key没有映射的话,返回null。
 * 				 (如果实现支持null值,返回null也可以表明前一个与key关联的是)
 * @throws UnsupportedOperationException 如果此Map不支持put操作
 * @throws ClassCastException 如果指定的key或value的类阻止它存储在此Map中
 * @throws NullPointerException 如果指定的value或value为null,并且此Map不允许null
 * @throws IllegalArgumentException 如果指定的key或value的某些属性阻止将其存储在此Map中
 */
V put(K key, V value);

/**
 * 如果key存在,则从该映射中删除该key的映射(可选操作)。
 * 更正式地说,如果这个映射包含一个从key k到value v的映射,使得(key==null ?k==null: key.equals(k))
 * 该映射被删除。(Map最多可以包含一个这样的映射。)
 *
 * 返回此映射以前与key关联的value,或者null(如果映射不包含key的映射)。
 *
 * 如果此映射允许空值,则null的返回值不一定表示该Map不包含key的映射;
 * 也有可能映射显式地将key映射到null。
 *
 * 一旦调用返回,Map将不包含指定key的映射。
 *
 * @throws UnsupportedOperationException 如果此Map不支持remove操作
 * @throws ClassCastException 如果key的类型不适合此Map
 * @throws NullPointerException 如果指定的key为null,并且此Map不允许null
 */
V remove(Object key);


// Bulk Operations 批量操作

/**
 * 将指定Map的所有映射复制到此Map(可选操作)。
 * 相当于在对于从key k到指定Map中的value v的每个映射上调用一次put(k, v)。
 * 如果在操作过程中修改了指定的Map,则此操作的行为未定义。
 *
 * @throws UnsupportedOperationException 如果此Map不支持putAll操作
 * @throws ClassCastException 如果指定Map中的key或value的类阻止将其存储在此Map中
 * @throws NullPointerException 如果指定的map为null,或者指定的Map包含的key或value为null,而Map不允许 
 * 				 null
 * @throws IllegalArgumentException 如果指定Map中的key或value的某些属性阻止将其存储在此Map中
 */
void putAll(Map<? extends K, ? extends V> m);

/**
 * 从该Map中删除所有映射(可选操作)。这个调用返回后,Map将为空。
 *
 * @throws UnsupportedOperationException 如果此Map不支持clear操作
 */
void clear();


// Views 视图,三种,Set->key Collection->value Set->entry

/**
 * 返回此映射中包含的key的Set视图。
 * Set由Map支持,因此对Map的更改将反映在Set中,反之亦然。
 * 如果在对Set进行迭代时修改了Map(除了通过迭代器自己的删除操作),则迭代的结果是未定义的。
 * Set支持删除元素,它通过Iterator.remove,Set.remove,removeAll,retainAll和clear操作
 * 从Map中删除对应的映射。它不支持add或addAll操作。
 */
Set<K> keySet();

/**
 * 返回此Map中包含的value的Collection视图。
 * Collection由Map支持,因此对Map的更改反映在Collection中,反之亦然。
 * 如果在Collection的迭代过程中修改了Map(除了通过迭代器自己的删除操作),则迭代的结果是未定义的。
 * Collection支持元素删除,它通过Iterator.remove,Collection.remove,removeAll,retainAll和clear操作
 * 从Map中删除对应的映射。它不支持add或addAll操作。
 */
Collection<V> values();

/**
 * 返回此Map中包含的entry的Set视图。
 * Set由Map支持,因此对Map的更改将反映在Set中,反之亦然。
 * 如果在对Set进行迭代时修改了Map
 * (除了通过迭代器自己的删除操作,或者通过迭代器返回的entry的setValue操作),迭代的结果是未定义的。
 * Set支持元素删除,它通过Iterator.remove, Set.remove, removeAll, retainAll和clear操作
 * 从Map中删除对应的映射。它不支持add或addAll操作。
 */
Set<Map.Entry<K, V>> entrySet();

2. AbstractMap抽象类

1) SimpleEntry

/**
 * 一个包含key和value的entry。可以使用setValue方法更改value值。
 * 该类简化了构建自定义Map实现的过程。
 * 例如,在Map.entrySet().toArray方法中返回SimpleEntry数组可能比较方便。
 * 
 * 其方法都是按照Entry接口实现的,比较简单,大家简单看一下就好。
 */
public static class SimpleEntry<K,V>
    implements Entry<K,V>, java.io.Serializable
{
    private static final long serialVersionUID = -8499721149061103585L;

    private final K key;
    private V value;

    public SimpleEntry(K key, V value) {
        this.key   = key;
        this.value = value;
    }

    public SimpleEntry(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) {
        V oldValue = this.value;
        this.value = value;
        return oldValue;
    }


    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());
    }

    public int hashCode() {
        return (key   == null ? 0 :   key.hashCode()) ^
               (value == null ? 0 : value.hashCode());
    }

    public String toString() {
        return key + "=" + value;
    }

}

2) SimpleImmutableEntry

/**
 * 一个保持不变key和value的entry。
 * 这个类不支持setValue方法。这个类在返回键值映射的线程安全快照的方法中可能很方便。
 * 
 * 同样比较简单,大家看一下就好
 */
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;
    }

  	// 不支持setValue方法
    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());
    }

    public int hashCode() {
        return (key   == null ? 0 :   key.hashCode()) ^
               (value == null ? 0 : value.hashCode());
    }

    public String toString() {
        return key + "=" + value;
    }
}

3) 方法实现

public boolean containsValue(Object value) {
  	// 获取迭代器
    Iterator<Entry<K,V>> i = entrySet().iterator();
    if (value==null) {
      	// 查找null的情况
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getValue()==null)
                return true;
        }
    } else {
      	// 查找value非空的情况
        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;
}

// 同样通过迭代器查找
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;
}


// Modification Operations

// 不支持put方法
public V put(K key, V value) {
    throw new UnsupportedOperationException();
}

public V remove(Object key) {
  	// 首先通过迭代器找目标entry,找到或遍历结束退出循环
    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;
        }
    }
		
  	// 如果找到目标entry,调用迭代器remove方法移除
    V oldValue = null;
    if (correctEntry !=null) {
        oldValue = correctEntry.getValue();
        i.remove();
    }
  	// 返回删除entry的value
    return oldValue;
}

// Bulk Operations

// 使用foreach遍历entrySet,调用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的clear方法
public void clear() {
    entrySet().clear();
}


// Views 视图,三种,Set->key Collection->value Set->entry

transient Set<K>        keySet;
transient Collection<V> values;

public Set<K> keySet() {
    Set<K> ks = keySet;
    if (ks == null) {
      	// 创建一个匿名类,重写AbstractSet方法
        // 方法都是调用AbstractMap的相关方法
        ks = 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);
            }
        };
        keySet = ks;
    }
    return ks;
}

public Collection<V> values() {
    Collection<V> vals = values;
    if (vals == null) {
	      // 创建一个匿名类,重写AbstractCollection方法
        // 方法都是调用AbstractMap的相关方法
        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 abstract Set<Entry<K,V>> entrySet();


// Comparison and hashing

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 {
      	// 使用迭代器遍历entrySet,判断对于相同的key,二者的value是否相等
        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;
}

// 所有entry的hashCode和
public int hashCode() {
    int h = 0;
    Iterator<Entry<K,V>> i = entrySet().iterator();
    while (i.hasNext())
        h += i.next().hashCode();
    return h;
}

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(' ');
    }
}

protected Object clone() throws CloneNotSupportedException {
    AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
    result.keySet = null;
    result.values = null;
    return result;
}

private static boolean eq(Object o1, Object o2) {
    return o1 == null ? o2 == null : o1.equals(o2);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值