Java HashMap

HashMap 实现了 Map 接口,其内部利用键的哈希值保证键的唯一性。在本教程中,我们将通过示例了解 Java HashMap 类及其各种操作。

在本教程中,我们将通过示例了解 Java HashMap 类及其各种操作。

Java 集合框架的 HashMap 类提供散列表数据结构的功能。

HashMap 将元素按键/值对存储,在这个结构中,我们通过是来关联,并且具有唯一性。

HashMap 类实现了 Map 接口,其内部利用键的哈希值保证键的唯一性。

Java HashMap 实现 Map 接口
Java HashMap 实现

创建 HashMap

我们导入 java.util.HashMap 类后,就可以通过构造方法创建 HashMap 对象了。

HashMap<K, V> numbers = new HashMap<>();

在上面的代码中,我们创建了一个名为 numbers 的 HashMap 对象。 这里,K 代表键类型,V 代表值的类型。例如,

HashMap<String, Integer> numbers = new HashMap<>();

String 类型,的值Integer 类型。

示例 1:在 Java 中创建 HashMap

import java.util.HashMap;

public class Main {
  public static void main(String[] args) {
    HashMap<String, Integer> languages = new HashMap<>();

    languages.put("Java", 8);
    languages.put("JavaScript", 1);
    languages.put("Python", 3);
    System.out.println("HashMap: " + languages);
  }
}

输出

HashMap: {Java=8, JavaScript=1, Python=3}

在上面的例子中,我们创建了一个 HashMap 对象 languages,并使用了 put() 向添加键值对数据。

Java HashMap 的基本操作

HashMap 类提供了许多方法来执行不同的操作。主要包括:

  • 添加元素
  • 访问元素
  • 更改元素
  • 删除元素

向 HashMap 添加元素

put() 方法用于将键值对元素添加到 HashMap 。例如,

import java.util.HashMap;

public class Main {
  public static void main(String[] args) {

    HashMap<String, Integer> numbers = new HashMap<>();
    System.out.println("Initial HashMap: " + numbers);

    numbers.put("One", 1);
    numbers.put("Two", 2);
    numbers.put("Three", 3);
    System.out.println("HashMap after put(): " + numbers);
  }
}

输出

Initial HashMap: {}
HashMap after put(): {One=1, Two=2, Three=3}

注意声明,

numbers.put("One", 1);

在这里,我们使用 put() 方法添加 String 类型的键和 Integer 类型的值到 Hash Map 中。

访问 HashMap 元素

get() 方法获取指定的键对应的值。例如,

import java.util.HashMap;

public class Main {
  public static void main(String[] args) {

    HashMap<Integer, String> languages = new HashMap<>();
    languages.put(1, "Java");
    languages.put(2, "Python");
    languages.put(3, "JavaScript");
    System.out.println("HashMap: " + languages);

    String value = languages.get(1);
    System.out.println("Value at index 1: " + value);
  }
}

输出

HashMap: {1=Java, 2=Python, 3=JavaScript}
Value at index 1: Java

在上面的例子中,注意表达式,

languages.get(1);

在这里, get() 方法将作为其参数并返回与键关联的

我们还可以访问键/值使用 HashMap 中的对作为一组的意见 keySet()values()entrySet() 分别的方法。例如,

我们还可以使用以下方法:

  • keySet(): 返回所有键的 Set 集合
  • values(): 返回所有值的集合
  • entrySet():返回所有键值对条目的 Set 集合
import java.util.HashMap;

public class Main {
  public static void main(String[] args) {
    HashMap<Integer, String> languages = new HashMap<>();

    languages.put(1, "Java");
    languages.put(2, "Python");
    languages.put(3, "JavaScript");
    System.out.println("HashMap: " + languages);

    System.out.println("Keys: " + languages.keySet());
    System.out.println("Values: " + languages.values());
    System.out.println("Key/Value mappings: " + languages.entrySet());
  }
}

输出

HashMap: {1=Java, 2=Python, 3=JavaScript}
Keys: [1, 2, 3]
Values: [Java, Python, JavaScript]
Key/Value mappings: [1=Java, 2=Python, 3=JavaScript]

更改 HashMap 值

replace() 方法更改指定的键关联的值。例如,

import java.util.HashMap;

public class Main {
  public static void main(String[] args) {

    HashMap<Integer, String> languages = new HashMap<>();
    languages.put(1, "Java");
    languages.put(2, "Python");
    languages.put(3, "JavaScript");
    System.out.println("Original HashMap: " + languages);

    // 修改键 2 对应的值
    languages.replace(2, "C++");
    System.out.println("HashMap using replace(): " + languages);
  }
}

输出

Original HashMap: {1=Java, 2=Python, 3=JavaScript}
HashMap using replace(): {1=Java, 2=C++, 3=JavaScript}

移除 HashMap 元素

remove() 方法删除并返回指定键对应的条目。例如,

import java.util.HashMap;

public class Main {
  public static void main(String[] args) {

    HashMap<Integer, String> languages = new HashMap<>();
    languages.put(1, "Java");
    languages.put(2, "Python");
    languages.put(3, "JavaScript");
    System.out.println("HashMap: " + languages);

    // 删除键 2 对应的条目
    String value = languages.remove(2);
    System.out.println("Removed value: " + value);

    System.out.println("Updated HashMap: " + languages);
  }
}

输出

HashMap: {1=Java, 2=Python, 3=JavaScript}
Removed value: Python
Updated HashMap: {1=Java, 3=JavaScript}

我们也可以根据键和值删除对应的键值对条目。例如,

remove(2, "C++");

此处,该方法仅在删除键位 2 值位 "C++" 的键值对条目。只有键和值都匹配的条目才会被删除。如果删除成功返回 true,否则返回 false

HashMap 的其他方法

  • clear(): 清空 HashMap
  • compute(): 根据指定的键计算新值,并更新到条目。
  • computeIfAbsent(): 当指定键不存在或对应的值为 null 时,根据键计算新值,并更新。
  • computeIfPresent(): 当指定键不存在且对应的值不为 null 时,重新根据键计算新值并更新。
  • merge(): 将指定键的条目中的值与新指定的值通过指定的接口函数合并,并更新为合并后的值。如果指定的键不存在或者对应的值为 null,则更新为新指定的值。
  • clone(): 克隆 Hashmap
  • containsKey(): 检查 Hashmap 中是否存在指定的键
  • containsValue(): 检查 Hashmap 中是否包含指定的值
  • size(): 返回 HashMap中键值对条目的数量
  • isEmpty(): 检查 Hashmap 是否为空

遍历 HashMap

我们可以使用 Java for-each 循环遍历 Hashmap 的每个条目。例如,

import java.util.HashMap;
import java.util.Map.Entry;

public class Main {
  public static void main(String[] args) {

    // create a HashMap
    HashMap<Integer, String> languages = new HashMap<>();
    languages.put(1, "Java");
    languages.put(2, "Python");
    languages.put(3, "JavaScript");
    System.out.println("HashMap: " + languages);

    // 只遍历键
    System.out.print("Keys: ");
    for (Integer key : languages.keySet()) {
      System.out.print(key);
      System.out.print(", ");
    }

    // 只遍历值
    System.out.print("\nValues: ");
    for (String value : languages.values()) {
      System.out.print(value);
      System.out.print(", ");
    }

    // 遍历键值对条目
    System.out.print("\nEntries: ");
    for (Entry<Integer, String> entry : languages.entrySet()) {
      System.out.print(entry.getKey() + "=" + entry.getValue());
      System.out.print(", ");
    }
  }
}

输出

HashMap: {1=Java, 2=Python, 3=JavaScript}
Keys: 1, 2, 3,
Values: Java, Python, JavaScript,
Entries: 1=Java, 2=Python, 3=JavaScript,

请注意,我们在上面的示例中使用了 Map.Entry 类。它是 Map 接口中的嵌套类,它代表了一个键值对条目。 Map.Entry 类由 3 个主要的方法:

  • getKey(): 返回键值对条目中的键
  • getValue(): 返回键值对条目中的值
  • setValue(V value): 设置键值对条目中的值。

从其他 Map 创建 HashMap

在 Java 中,我们还可以从其他映射创建 HashMap。例如,

import java.util.HashMap;
import java.util.TreeMap;

public class Main {
  public static void main(String[] args) {

    // 创建 TreeMap
    TreeMap<String, Integer> evenNumbers = new TreeMap<>();
    evenNumbers.put("Two", 2);
    evenNumbers.put("Four", 4);
    System.out.println("TreeMap: " + evenNumbers);

    // 从现有的 map 创建一个 HashMap 对象
    HashMap<String, Integer> numbers = new HashMap<>(evenNumbers);
    numbers.put("Three", 3);
    System.out.println("HashMap: " + numbers);
  }
}

输出

TreeMap: {Four=4, Two=2}
HashMap: {Two=2, Three=3, Four=4}

在上面的例子中,我们创建了一个名为 evenNumbersTreeMap 对象。 注意这面的语句:

numbers = new HashMap<>(evenNumbers)

在这里,我们使用了带参数的构造方法 HashMap(Map<? extends K, ? extends V> m),将一个现有的 Map 对象转为 HashMap 对象。

HashMap 容量和负载因子

在创建 HashMap 时,我们通过构造函数指定它的初始容量大小,由两个相关的构造函数:

  • HashMap(int initialCapacity): 指定初始容量大小,负载因子默认为 0.75f
  • HashMap(int initialCapacity, float loadFactor): 指定初始容量大小和负载因子

参数如下:

  • initialCapacity: 初始容量大小,默认为 16
  • loadFactor: 负载因子,负载因子默认为 0.75f。浮负载因子用来指示当容量达到指定的负载占比时,就要对容量扩容。

例如:

HashMap<K, V> numbers = new HashMap<>(8, 0.6f);

这里,

  • 初始容量为 8: 初始分配的大小为 8
  • 负载因子为 0.6f: 意味着每当使用量超过 60% 时,就要对底层的存储扩容,一般是变为原来的 2 倍。