Java集合源码分析(十四)-Map(一)类和抽象方法

235 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

源码

public interface Map<K,V> {
// Query Operations

    int size();

    boolean isEmpty();

    boolean containsKey(Object key);

    boolean containsValue(Object value);

    V get(Object key);

    // Modification Operations

    V put(K key, V value);

    V remove(Object key);

    // Bulk Operations

    void clear();

    // Views

    Set<K> keySet();

    Collection<V> values();

    Set<Map.Entry<K, V>> entrySet();

    // Comparison and hashing

    boolean equals(Object o);

    int hashCode();
}

注释内容

  • 映射 key 到 values 的对象。map 不能包含重复 keys,每一个 key 最多能映射一个 value

  • 这个接口代替 Dictionary 类,Dictionary 类是抽象类而不是接口

  • Map 接口提供三个集合视图,允许 map 的内容被视为 keys 集合,values 集合,或者 key-value 映射的集合

  • map 的顺序是定义为 map 集合视图上迭代器返回元素的顺序

  • 一些 map 实现,像 TreeMap 类,对它们的顺序做特殊的保证;其他,像 HashMap 类,没有

  • 注意:必须非常小心使用,如果可变对象被用作 map keys

  • 如果当对象是 map 中的 key 时,对象值被以影响 equals 比较的方式改变,map 的行为没有指定

  • 这个禁令的一种特殊情况是不允许 map 包含他自己作为 key

  • 虽然允许 map 包含它自己作为 value,建议特别小心:在这样的 mape 上,quals 和 hashCode 方法不再很好定义

  • 所有多功能的 map 实现类应该提供两个“标准”构造函数:一个 void(无参)构造创建空 map,和一个有单个 Map 类型参数的构造函数,这个构造器创建一个新的 map,和它的参数有相同 key-value 映射。实际上,后一个构造函数允许使用者复制任何 map,产生所需类的相同 map

  • 无法强制这个建议(因为接口不能包含构造器),但 JDK 全部多功能的 map 遵循这个建议

  • 这个接口包含 destructive 方法,也就是说,它们操作修改 map 的方法,如果这个 map 不支持这个操作,指定抛出 UnsupportedOperationException

  • 如果是这种情况,如果调用对 map 没有任何影响,这些方法可能(但不要求)抛出 UnsupportedOperationException

  • 例如,如果 map 映射“叠加”是空,在不能修改的 map 调用 putAll(Map) 方法可能会抛出异常,但这不是要求的

  • 一些 map 实现对它们可能包含的 keys 和 values 有限制。例如,一些实现禁止 null key 和 value,有些对它们 keys 的类型有限制。

  • 试图插入不合格的 key 或 value 抛出未检查异常,典型的 NullPointerException 或 ClassCastException

  • 试图查询是否存在不合格的 key 或 value 可能抛出异常,或它可能简单返回 false;一些实现将显示前一种行为,一些将显示后一种

  • 更一般的说,试图操作不合格的 key 或者 value,key 或 value 的完成不会导致插入不合格的元素到 map,可能抛出异常或它可能成功,取决实现的选择

  • 这样的异常在这个接口的规范被标记为“可选”

  • 集合框架接口的很多方法定义依据 equals 方法

  • 例如,containsKey(Object key) 方法规范说,“返回 true,当且仅当这个 map 包含 key k,使得 (key==null ? k==null : key.equals(k))”

  • 这个规范不应该解释成暗示通过非空参数 key 调用 Map.containsKey 将引起任何 key k 调用 key.equals(k)

  • 实现可以自由实现优化,从而避免 equals 调用,例如,首先比较两个 keys 的哈希编码(hasCode() 规范保证哈希编码不等的两个对象不能相等)

  • 更一般的说,各种集合框架接口的实现可以自由利用底层 Object 方法,只要实现者认为它合适

  • 一些执行递归遍历 map 的 map 操作可能失败,map 直接或间接包含自己的自引用实例除外

  • 这包括 clone(),equals(),hashCode 和 toString() 方法,实现可以选择性处理自引用场景,然后大多数当前实现都没有这样做

方法内容

  • 查询操作
    • int size():返回这个 map 的键值对映射的数量,如果 map 包含超过 Integer.MAX_VALUE 元素,返回 Integer.MAX_VALUE
    • boolean isEmpty():返回 true,如果这个 map 没有包含键值对映射
    • boolean containsKey(Object key):返回 true,如果这个 map 包含指定 key 的映射。更准确的说,返回 true,当且仅当这个 map 包含键 k (key==null ? k==null : key.equals(k))的映射(最多可以有一个这样的映射)
    • boolean containsValue(Object value):返回 true,如果这个 map 映射一个或多个 key 到指定 value。更准确的说,返回 true,当且仅当如果这个 map 包含至少一个映射到一个 value,使得 (value==null ? v==null : value.equals(v))。对大部分 Map 接口的实现,这个操作将可能需要 map 大小的线性时间
    • V get(Object key):返回指定 key 映射的 value ,或者 null,如果这个 map 没有包含这个 key 的映射
      • 更准确的说,如果这个 map 包含映射从 k 到 v,使得 (key==null ? k==null : key.equals(k)),然后这个方法返回 v,否则它返回 null(最多可以有一个这样的映射)
      • 如果这个 map 允许 null 值,那么返回 null 值不一定表示 map 不包含这个 key 的映射。这同样可能显式映射 key 为 null。containsKey 操作可用于区分这两种方式
  • 修改操作
    • V put(K key, V value):将指定 value 和指定 key 关联(可选操作)。如果 map 之前包含 key 的映射,旧值被替代为指定值(当且仅当 m.containKey(k) 返回 true 时,map m 被称为包含 key k 映射)
    • V remove(Object key):从这个 map 移除 key 的映射,如果它存在(可选操作)。更准确的说,如果这个 map 包含从 kye k 到 value v 的映射,使得 (key==null ? k==null : key.equals(k)),这个映射被移除(map 最多包含一个这样的映射)
      • 返回 这个 map 之前关联 key 的 value,或者 null,如果 map 没有包含 key 的映射
      • 如果这个 map 允许 null 值,因此返回 null 值不一定表示 map 不包含这个 key 的映射。这同样可能显式映射 key 为 null
      • map 将不包含指定 key 的映射,一旦调用返回
  • 批量操作
    • void putAll(Map<? extends K, ? extends V> m);:复制指定 map 的全部映射到这个 map(可选操作)。这个调用的效果和在指定 map 的每个从 key k 到 value v 的映射调用一次 put(k,v) 一致。这个操作的行为是未定义,如果在操作过程中,指定 map 被修改
    • void clear():移除这个 map 的全部映射(可选操作)。这个调用返回之后 map 将变为空
    • Set<K> keySet();:返回这个 map 包含 key 的 Set 视图。set 由 map 支持,因此改变 map 会反应在 set,反之亦然。如果在迭代 set 的过程中, map 被修改(除非通过迭代器拥有的 remove 操作),迭代器的结果是未定义的。set 支持元素移除,从 map 移除一致的映射,通过 Iterator.remove,Set.remove,removeAll,retainAll,和 clear 操作。不支持 add 或者 addAll 操作
    • Collection<V> values();:返回这个 map 包含的 value 的 Collection 视图。collection 由 map 支持,因此改变 map 会反应在 视图。collection,反之亦然。如果在迭代 视图。collection 的过程中, map 被修改(除非通过迭代器拥有的 remove 操作),迭代器的结果是未定义的。视图。collection 支持元素移除,从 map 移除一致的映射,通过 Collection.remove,removeAll,retainAll,和 clear 操作。不支持 add 或者 addAll 操作
    • Set<Map.Entry<K, V>> entrySet():返回这个 map 包含的映射 Set 视图。这个 set 由 map 因此改变 map 会反应在 set,反之亦然。如果在迭代 set 的过程中, map 被修改(除非通过迭代器拥有的 remove 操作,或者通过迭代器返回的 map entry 里的 setValue 操作),迭代器的结果是未定义的。 set 支持元素移除,从 map 移除一致的映射,通过 Iterator.remove,Set.remove,removeAll,retainAll,和 clear 操作。不支持 add 或者 addAll 操作
  • 比较和哈希
    • boolean equals(Object o):指定对象和这个 map 相等性比较。返回 true,如果给定对象同样是 map 并且两个 map 代表相同的映射。更准确的说,两个 map m1 和 m2 代表相同映射,如果 m1.entrySet().equals(m2.entrySet())。这可确保 equals 方法在 Map 接口不同的实现中正常工作
    • int hashCode():返回这个 map 的哈希编码值。map 的哈希编码定义为 map 的 entrySet() 视图中每一个 entry 的哈希编码和。这确保对于任何两个 map m1 和 m2,m1.equals(m2) 意味着 m1.hashCode()==m2.hashCode(),按照 Object.hashCode 的总合同要求