Java Map – HashMap

Java Map – HashMap

Java 中的 HashMap 是一个集合类,它实现了Map接口。它用于存储k-v键值对,每个键都映射到Map中的某个值。

键是唯一的,这意味着我们只能在Map中插入一次键 ‘k’,不允许使用重复的 key,虽然一个值’v’可以映射到多个 key。

HashMap 是 JDK 中非常重要的一个类,其源码的阅读价值极大,强烈建议 Java 开发者吃透 HashMap。

java.util.HashMap 类

HashMap 层次结构

HashMap 特性

  • HashMap 不能包含重复的键。
  • HashMap 允许多个null值但只有一个null键。
  • HashMap 是一个无序集合。它不保证元素的任何特定顺序。
  • HashMap 不是线程安全的。对 HashMap 的并发修改必须显式同步,或者可以使用Collections.synchronizedMap(hashMap)来获取 HashMap 的同步版本。
  • HashMap 只能使用关联的键检索值。
  • HashMap 只存储对象引用,所以基本数据类型必须与其对应的包装类一起使用,如int将存储为Integer.
  • HashMap 实现了Cloneable和Serializable接口。

HashMap 内部实现

HashMap 的工作原理是 hash 散列,散列是一种在将任何公式/算法应用于其属性后为任何变量/对象分配唯一码的方法。Java 中的每个对象都有它的哈希码,这样两个相等的对象必须一致地产生相同的哈希码。

HashMap.Entry 类

键值对存储为静态内部类,HashMap.Entry将键和值映射存储为内部类属性,键已标记为final。

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
}

Entry 类的所有实例都存储在一个数组中,声明为’transient Entry[] table’。对于要存储在 HashMap 中的每个键值,使用键的哈希码计算一个哈希值。该哈希值用于计算数组中用于存储 Entry 对象的索引。

在碰撞的情况下,其中多个键被映射到单个索引位置,形成一个链表来存储所有应该进入单个数组索引位置的键值对。

通过键检索值时,使用键的哈希码找到第一个索引位置,然后在链表中迭代所有元素,并通过使用它的equals()方法识别正确的键来找到正确的值对象。

Java HashMap 示例

添加键值对 put()

private static void test1(){
    Map<Integer, String> map = new HashMap<>();
    map.put(1, "Ada");
    map.put(2, "Bob");
    map.put(3, "Chery");

    System.out.println(map);
}
{1=Ada, 2=Bob, 3=Chery}

获取值 get()

private static void findMap(){
    Map<Integer, String> map = new HashMap<>();
    map.put(1, "Ada");
    map.put(2, "Bob");
    map.put(3, "Chery");

    // 通过 key 获取 value
    System.out.println(map.get(3));
    // 获取所有的 key ,返回一个列表
    System.out.println(map.keySet());
    // 获取虽有的 value,返回一个列表
    System.out.println(map.values());
    // 获取所有的键值对,返回一个列表
    System.out.println(map.entrySet());
}
Chery
[1, 2, 3]
[Ada, Bob, Chery]
[1=Ada, 2=Bob, 3=Chery]

通过key删除value remove()

private static void removeMap(){
    Map<Integer, String> map = new HashMap<>();
    map.put(1, "Ada");
    map.put(2, "Bob");
    map.put(3, "Chery");

    // 通过 key 删除一个元素
    System.out.println(map.remove(1));
    System.out.println(map);
    // 通过 key 删除一个元素一个不存在的元素
    System.out.println(map.remove(5));
    System.out.println(map);

    // 通过 Key 与 value 删除一个元素
    System.out.println(map.remove(2, "Bob"));
    System.out.println(map);

    // 通过 Key 与 value 删除一个元素,key 与 value 不匹配
    System.out.println(map.remove(3, "Jack"));
    System.out.println(map);

}
Ada
{2=Bob, 3=Chery}
null
{2=Bob, 3=Chery}
true
{3=Chery}
false
{3=Chery}

遍历所有元素

private static void forEachMap(){
    Map<Integer, String> map = new HashMap<>();
    map.put(1, "Ada");
    map.put(2, "Bob");
    map.put(3, "Chery");

    // 最常用的迭代方式
    for(Map.Entry<Integer, String> entry: map.entrySet()){
        System.out.println("key "+ entry.getKey() + ", value " + entry.getValue());
    }
    System.out.println("-------- 分割线 --------");

    // 迭代器方式
    Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
    while(iterator.hasNext()){
        Map.Entry<Integer, String> entry = iterator.next();
        System.out.println("key "+ entry.getKey() + ", value " + entry.getValue());
    }
    System.out.println("-------- 分割线 --------");
    // lambda 方式
    map.forEach((k,v) -> System.out.println("key "+ k + ", value " + v));
}
key 1, value Ada
key 2, value Bob
key 3, value Chery
——– 分割线 ——–
key 1, value Ada
key 2, value Bob
key 3, value Chery
——– 分割线 ——–
key 1, value Ada
key 2, value Bob
key 3, value Chery

HashMap 重要方法

方法签名 释义
void clear() 从 HashMap 中删除所有键值对。
Object clone() 返回指定 HashMap 的浅拷贝。
boolean containsKey(Object key) 返回true或false基于是否在HashMap中找到指定的键。
boolean containsValue(Object Value) 类似于 containsKey() 方法,它查找指定的值而不是键。
Object get(Object key) 返回 HashMap 中指定键的值。
boolean isEmpty() 检查HashMap是否为空。
Set keySet() 返回存储在 HashMap 中的所有键的Set。
Object put(Key k, Value v) 将键值对插入到 HashMap 中。
int size() 返回映射的大小,它等于存储在 HashMap 中的键值对的数量。
Collection values() 返回HashMap中所有值的集合。
Value remove(Object key) 删除指定键的键值对。
void putAll(Map m) 将HashMap的所有元素复制到另一个指定的HashMap。
转载请注明出处:码谱记录 » Java Map – HashMap
标签: