java-Map

5243 字
14 分钟

每日一言

正因为没有翅膀,人们才会寻找飞翔的方法。

——《排球少年》

HashMap

HashMap 类位于 java.util 包中,使用前需要引入:

import java.util.HashMap; // 引入 HashMap 类

创建一个HashMap,我们需要传入key和value的数据类型:

HashMap<Integer, String> Sites = new HashMap<Integer, String>();
  • HashMap中依旧需要使用包装类

创参数

  1. initialCapacity(初始容量):

    • 含义:指定HashMap内部哈希表(数组)的初始大小
    • 目的 : 如果预先知道大概要存储多少个键值对,设置一个合适的初始容量可以减少 HashMap 在后续添加元素时进行扩容(resize/rehash)的次数。扩容操作是比较耗时的,因为它需要创建一个更大的数组,并将所有现有元素重新计算哈希和位置放入新数组。
    • 默认值:可以不指定,默认为16
    • 注意事项:HashMap的实际容量是2的幂次方。如果你提供的 initialCapacity 不是2的幂,HashMap会将其调整为大于等于你提供的值的最小的2的幂次方。
  2. loadFactor(加载因子):

    • 含义:一个介于0.0 到 1.0 之间的浮点数,它决定了HashMap在其容量达到多大比例时进行扩容。

    • 目的 : 控制空间利用率和查找时间之间的平衡。

      • 较高的加载因子 (例如 0.9):意味着 HashMap 会等到内部数组填充得更满时才扩容。这可以节省空间,但会增加哈希冲突的可能性,从而可能降低查找、插入、删除的平均性能(因为链表或红黑树会更长/更深)。
      • 较低的加载因子 (例如 0.5):意味着 HashMap 在内部数组还比较空的时候就会扩容。这会占用更多空间(因为数组更大),但能减少哈希冲突,从而可能提高平均性能。
    • 默认值 : 如果不指定,默认为 0.75f。这个值通常在时间和空间成本之间提供了一个较好的折衷。

    • 计算扩容阈值:扩容发送在HashMap中的元素超过 capacity*loadFactor 时。

常用方法

添加键值对

// 2. 添加键值对 (put)
studentScores.put("Alice", 95);
studentScores.put("Bob", 88);
studentScores.put("Charlie", 92);
studentScores.put("David", 76);

// 如果键已存在,put 会覆盖旧值,并返回旧值
Integer oldScoreBob = studentScores.put("Bob", 90); // Bob's score updated to 90
System.out.println("Bob's old score: " + oldScoreBob); // 输出: Bob's old score: 88
System.out.println("Current map: " + studentScores); // 输出: Current map: {David=76, Alice=95, Bob=90, Charlie=92} (顺序不保证)

获取值

// 3. 获取值 (get)
Integer aliceScore = studentScores.get("Alice");
System.out.println("Alice's score: " + aliceScore); // 输出: Alice's score: 95

// 如果键不存在,get 返回 null
Integer frankScore = studentScores.get("Frank");
System.out.println("Frank's score: " + frankScore); // 输出: Frank's score: null

检查键或值是否存在

// 4. 检查键或值是否存在 (containsKey / containsValue)
boolean hasAlice = studentScores.containsKey("Alice");
System.out.println("Contains key 'Alice'? " + hasAlice); // 输出: Contains key 'Alice'? true

boolean hasScore100 = studentScores.containsValue(100);
System.out.println("Contains value 100? " + hasScore100); // 输出: Contains value 100? false

删除键值对

// 5. 删除键值对 (remove)
Integer removedScore = studentScores.remove("David"); // 返回删除键的值
System.out.println("Removed David's score: " + removedScore); // 输出: Removed David's score: 76
System.out.println("Map after removing David: " + studentScores); // 输出: Map after removing David: {Alice=95, Bob=90, Charlie=92}

获取Map大小

// 6. 获取 Map 大小 (size)
int size = studentScores.size();
System.out.println("Map size: " + size); // 输出: Map size: 3

检查是否为空

// 7. 检查是否为空 (isEmpty)
boolean isEmpty = studentScores.isEmpty();
System.out.println("Is map empty? " + isEmpty); // 输出: Is map empty? false

遍历Map

keySet()

keySet() 方法返回一个 Set<K> 其中K是HashMap中键的类型。这个Set<>包含HashMap中当前存储的所有键。

关键特性:

  • 视图(View):返回的Set是HashMap 的一个视图,而不是一个独立的副本。
    • 对map的更改会反应在Set中。
    • 对Set的更改(仅限删除)会反应在Map中。
    • 不支持添加:尝试添加会抛出异常。
  • 无序(对于HashMap):Set中的键不保证任何特定的顺序,如果你需要有序的键集合, 应该使用 LinkedHashMapTreeMap

使用keySet()遍历Map的方法如下:

// 输出 key 和 value
for (Integer i : Sites.keySet()) {
    System.out.println("key: " + i + " value: " + Sites.get(i));
}

values()

HashMap的values()方法返回一个 java.util.Collection<V> ,其中V是Map中Value的类型。这个Collection 包含当前所存储的所有值。

关键特性:

  • 返回类型是一个实现了Collection接口的实例,而不是具体的List或Set.
    • 可能包含重复值
    • 通常无序
  • 视图:
    • 对Map的修改会反映在Collection中。
    • 对Collection的更改(仅限删除)会反映在Map中,会删除所有对应值的键。
    • 不支持添加。

返回所有value的值:

// 输出 key 和 value
for (Integer i : Sites.keySet()) {
    System.out.println("key: " + i + " value: " + Sites.get(i));
}

HashMap常用方法

方法描述
clear()删除 hashMap 中的所有键/值对
clone()复制一份 hashMap
isEmpty()判断 hashMap 是否为空
size()计算 hashMap 中键/值对的数量
put()将键/值对添加到 hashMap 中
putAll()将所有键/值对添加到 hashMap 中
putIfAbsent()如果 hashMap 中不存在指定的键,则将指定的键/值对插入到 hashMap 中。
remove()删除 hashMap 中指定键 key 的映射关系
containsKey()检查 hashMap 中是否存在指定的 key 对应的映射关系。
containsValue()检查 hashMap 中是否存在指定的 value 对应的映射关系。
replace()替换 hashMap 中是指定的 key 对应的 value。
replaceAll()将 hashMap 中的所有映射关系替换成给定的函数所执行的结果。
get()获取指定 key 对应对 value
getOrDefault()获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值
forEach()对 hashMap 中的每个映射执行指定的操作。
entrySet()返回 hashMap 中所有映射项的集合集合视图。
keySet()返回 hashMap 中所有 key 组成的集合视图。
values()返回 hashMap 中存在的所有 value 值。
merge()添加键值对到 hashMap 中
compute()对 hashMap 中指定 key 的值进行重新计算
computeIfAbsent()对 hashMap 中指定 key 的值进行重新计算,如果不存在这个 key,则添加到 hashMap 中
computeIfPresent()对 hashMap 中指定 key 的值进行重新计算,前提是该 key 存在于 hashMap 中。

LinkedHashMap

LinkedHashMap = HashMap + 维护插入顺序的双向链表

在使用区别上,LinkedHashMap可以以插入顺序遍历Map。使用方法与HashMap一致。

TreeMap

TreeMap是 Java 集合框架中 Map接口的另一个重要实现。它的核心特点是能够 根据键(Key)的顺序来存储和访问键值对

  • 它保证了 Map 中的条目(Entries)总是按照键的 自然顺序 (natural ordering)或者在创建 Map 时提供的 Comparator进行排序。
  • 不允许null键,而允许null值

TreeMap也实现了Map接口,所以对于Map部分的操作方法与HashMap一致。

此外还实现了SortedMap和NavigableMap接口,这些部分这里不再深入,可以自行去了解。