# Java `HashMap`教程

原文：http://zetcode.com/java/hashmap/

Java `HashMap`教程显示了如何使用 Java `HashMap`集合。

## Java `HashMap`

`HashMap`是一个存储键值对的容器。 每个键与一个值关联。 `HashMap`中的键必须唯一。 `HashMap`在其他编程语言中称为关联数组或词典。 `HashMaps`占用更多内存，因为每个值还有一个键。 删除和插入操作需要固定的时间。 `HashMaps`可以存储空值。

`HashMaps`不维持秩序。

`Map.Entry`表示`HashMap`中的键/值对。 `HashMap`的`entrySet()`返回包含在映射中的映射的`Set`视图。 使用`keySet()`方法检索一组键。

## Java `HashMap`层次结构

`HashMap`扩展了`AbstractMap`并实现了`Map`。 `Map`提供了包括`get()`，`put()`，`size()`或`isEmpty()`的方法签名。

## Java `HashMap`构造器

*   `HashMap()`-构造一个空的`HashMap()`，其默认初始容量（16）和默认负载因子（0.75）。
*   `HashMap(int initialCapacity)`-构造一个空的`HashMap()`，具有给定的初始容量和默认的负载系数（0.75）。
*   `HashMap(int initialCapacity, float loadFactor)`-使用给定的初始容量和负载因子构造一个空的`HashMap()`。
*   `HashMap(Map<? extends K,? extends V> m)` —构造一个新的`HashMap()`，其映射与给定的`Map`相同。

`K`是映射键的类型，`V`是映射值的类型。

## Java `HashMap`方法

下表提供了几种`HashMap`方法。

| 修饰符和类型 | 方法 | 描述 |
| --- | --- | --- |
| `void` | `clear()` | 从映射中删除所有映射。 |
| `Object` | `clone()` | 返回`HashMap`实例的浅表副本：键和值本身不会被克隆。 |
| `boolean` | `containsKey(Object key)` | 如果此映射包含指定键的映射，则返回`true`。 |
| `Set<Map.Entry<K, V>>` | `entrySet()` | 返回此映射中包含的映射的`Set`视图。 |
| `boolean` | `isEmpty()` | 如果此映射为空，则返回`true`。 |
| `Set<K>` | `keySet()` | 返回此映射中包含的键的`Set`视图。 |
| `V` | `put(K key, V value)` | 向映射添加新的映射。 |
| `V` | `remove(Objec key)` | 如果存在，则从此映射中删除指定键的映射。 |
| `V` | `get(Object key)` | 返回指定键所映射到的值；如果此映射不包含键的映射关系，则返回`null`。 |
| `void` | `forEach(BiConsumer<? super K, ? super V> action)` | 在此映射中为每个条目执行给定的操作，直到所有条目都已处理或该操作引发异常。 |
| `V` | `replace(K key, V value)` | 仅当当前映射到某个值时，才替换指定键的条目。 |
| `int` | `size()` | 返回此映射中的键值映射数。 |
| `Collection<V>` | `values()` | 返回此映射中包含的值的`Collection`视图。 |

在本教程中，我们将使用其中的几种方法。

## Java `HashMap`创建

用`new`关键字创建`HashMap`。

```java
Map<String, String> capitals = new HashMap<>();

```

我们在尖括号之间指定键的类型和值。 由于类型推断，因此不必在声明的右侧提供类型。

## Java `HashMap put()`

`put()`方法用于向映射添加新的映射。

```java
capitals.put("svk", "Bratislava");

```

第一个参数是键，第二个是值。

## Java `HashMap remove()`

`remove()`方法用于从映射中删除一对。

```java
capitals.remove("pol");

```

参数是要从映射中删除其映射的键。

## Java `HashMap`初始化

从 Java 9 开始，我们有了用于`HashMap`初始化的工厂方法。

`com/zetcode/HashMapInit.java`

```java
package com.zetcode;

import java.util.Map;

import static java.util.Map.entry;

// factory initialization methods since Java 9
public class HashMapInit {

    public static void main(String[] args) {

        // up to 10 elements:
        Map<Integer, String> colours = Map.of(
                1, "red",
                2, "blue",
                3, "brown"
        );

        System.out.println(colours);

        // any number of elements
        Map<String, String> countries = Map.ofEntries(
                entry("de", "Germany"),
                entry("sk", "Slovakia"),
                entry("ru", "Russia")
        );

        System.out.println(countries);
    }
}

```

该示例使用`Map.of`和`Map.ofEntries`初始化哈希图。 这两个工厂方法返回不可修改的映射。

`com/zetcode/HashMapInit2.java`

```java
package com.zetcode;

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

// up to Java8
public class HashMapInit2 {

    public static void main(String[] args) {

        Map<String, String> countries = new HashMap<>() {{
            put("de", "Germany");
            put("sk", "Slovakia");
            put("ru", "Russia");
        }};

        System.out.println(countries);
    }
}

```

在此示例中，我们创建了一个可修改的哈希图。 这种初始化方式称为双括号哈希图初始化。

## Java `HashMap`大小示例

`HashMap`的大小由`size()`方法确定。

`com/zetcode/HashMapSize.java`

```java
package com.zetcode;

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

public class HashMapSize {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        int size = capitals.size();

        System.out.printf("The size of the HashMap is %d%n", size);

        capitals.remove("pol");
        capitals.remove("ita");

        size = capitals.size();

        System.out.printf("The size of the HashMap is %d%n", size);
    }
}

```

在代码示例中，我们创建`HashMap`并使用`size()`确定其大小。 然后，我们删除一些对，然后再次确定其大小。 我们将发现结果打印到控制台。

```java
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");

```

使用`put()`，我们将新的对添加到`HashMap`中。

```java
int size = capitals.size();

```

在这里，我们得到映射的大小。

```java
capitals.remove("pol");
capitals.remove("ita");

```

使用`remove()`，我们从映射中删除了两对。

```java
The size of the HashMap is 6
The size of the HashMap is 4

```

这是示例的输出。

## Java `HashMap get()`

要从`HashMap`检索值，我们使用`get()`方法。 它以键作为参数。

`com/zetcode/HashMapRetrieve.java`

```java
package com.zetcode;

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

public class HashMapRetrieve {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        String cap1 = capitals.get("ita");
        String cap2 = capitals.get("svk");

        System.out.println(cap1);
        System.out.println(cap2);
    }
}

```

在示例中，我们从映射中检索两个值。

```java
String cap2 = capitals.get("svk");

```

在这里，我们得到一个具有`"svk"`键的值。

## Java `HashMap clear()`

`clear()`方法从`HashMap`中删除所有对。

`com/zetcode/HashMapClear.java`

```java
package com.zetcode;

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

public class HashMapClear {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        capitals.clear();

        if (capitals.isEmpty()) {

            System.out.println("The map is empty");
        } else {

            System.out.println("The map is not empty");
        }
    }
}

```

在该示例中，我们删除了所有元素，并将映射的大小打印到控制台。

```java
capitals.clear();

```

我们用`clear()`删除所有对。

```java
if (capitals.isEmpty()) {

    System.out.println("The map is empty");
} else {

    System.out.println("The map is not empty");
}

```

使用`isEmpty()`方法，我们检查映射是否为空。

## Java `HashMap containsKey()`

如果映射包含指定键的映射，则`containsKey()`方法返回`true`。

`com/zetcode/HashMapContainsKey.java`

```java
package com.zetcode;

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

public class HashMapContainsKey {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        String key1 = "ger";
        String key2 = "rus";

        if (capitals.containsKey(key1)) {

            System.out.printf("HashMap contains %s key%n", key1);
        } else {

            System.out.printf("HashMap does not contain %s key%n", key1);
        }

        if (capitals.containsKey(key2)) {

            System.out.printf("HashMap contains %s key%n", key2);
        } else {

            System.out.printf("HashMap does not contain %s key%n", key2);
        }
    }
}

```

在示例中，我们检查映射是否包含两个键。

```java
if (capitals.containsKey(key1)) {

    System.out.printf("HashMap contains %s key%n", key1);
} else {

    System.out.printf("HashMap does not contain %s key%n", key1);
}

```

该`if`语句根据映射是否包含给定键输出消息。

```java
HashMap contains ger key
HashMap does not contain rus key

```

这是输出。

## Java `HashMap replace()`

有`replace()`方法使程序员可以替换条目。

```java
replace(K key, V value)

```

仅当当前映射到某个值时，此方法才替换指定键的条目。

```java
replace(K key, V oldValue, V newValue)

```

仅当当前映射到指定值时，此方法才替换指定键的条目。

`com/zetcode/HashMapReplace.java`

```java
package com.zetcode;

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

public class HashMapReplace {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("day", "Monday");
        capitals.put("country", "Poland");
        capitals.put("colour", "blue");

        capitals.replace("day", "Sunday");
        capitals.replace("country", "Russia", "Great Britain");
        capitals.replace("colour", "blue", "green");

        capitals.entrySet().forEach(System.out::println);
    }
}

```

在示例中，我们将映射中的对替换为`replace()`。

```java
capitals.replace("day", "Sunday");

```

在这里，我们替换`"day"`键的值。

```java
capitals.replace("country", "Russia", "Great Britain");

```

在这种情况下，由于密钥当前未设置为`"Russia"`，因此不会替换该值。

```java
capitals.replace("colour", "blue", "green");

```

由于旧值正确，因此将替换该值。

```java
country=Poland
colour=green
day=Sunday

```

这是输出。

## Java `HashMap`转换为`List`

在下一个示例中，我们将`HashMap`条目转换为条目列表。

`com/zetcode/HashMapConvert.java`

```java
package com.zetcode;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HashMapConvert {

    public static void main(String[] args) {

        Map<String, String> colours = Map.of(
                "AliceBlue", "#f0f8ff",
                "GreenYellow", "#adff2f",
                "IndianRed", "#cd5c5c",
                "khaki", "#f0e68c"
        );

        Set<Map.Entry<String, String>> entries = colours.entrySet();
        List<Map.Entry<String, String>> mylist = new ArrayList<>(entries);

        System.out.println(mylist);
    }
}

```

`entrySet()`返回映射的设置视图，该视图随后传递给`ArrayList`的构造器。

## 使用`forEach()`迭代`HashMap`

我们使用 Java8 `forEach()`方法来迭代`HashMap`的键值对。 `forEach()`方法对映射的每个元素执行给定的操作，直到所有元素都已处理或该操作引发异常。

`com/zetcode/HashMapForEach.java`

```java
package com.zetcode;

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

public class HashMapForEach {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        capitals.forEach((k, v) -> System.out.format("%s: %s%n", k, v));
    }
}

```

在代码示例中，我们使用 lambda 表达式迭代了`HashMap`和`forEach()`。

```java
capitals.forEach((k, v) -> System.out.format("%s: %s%n", k, v));

```

使用`forEach()`，我们遍历了映射的所有对。

## 使用增强的`for`循环迭代`HashMap`

Java 5 中引入的增强的`for`循环可用于对`HashMap`进行迭代。

`com/zetcode/HashMapEnhancedFor.java`

```java
package com.zetcode;

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

public class HashMapEnhancedFor {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        for (Map.Entry<String, String> pair: capitals.entrySet()) {

            System.out.format("%s: %s%n", pair.getKey(), pair.getValue());
        }
    }
}

```

在该示例中，我们迭代具有增强的`for`循环的`HashMap`。

```java
for (Map.Entry<String, String> pair: capitals.entrySet()) {

    System.out.format("%s: %s%n", pair.getKey(), pair.getValue());
}

```

在每个`for`周期中，都将新的键值对分配给`pair`变量。

## Java `HashMap`迭代键

我们可能只想遍历`HashMap`的键。

`com/zetcode/HashMapKeys.java`

```java
package com.zetcode;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class HashMapKeys {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        Set<String> keys = capitals.keySet();

        keys.forEach(System.out::println);
    }
}

```

该示例迭代`capitals`映射的键。

```java
Set<String> keys = capitals.keySet();

```

用`keySet()`方法检索`HashMap`的密钥，该方法返回密钥`Set`。 密钥必须唯一； 因此，我们有一个`Set`。 `Set`是一个不包含重复元素的集合。

```java
keys.forEach(System.out::println);

```

我们用`forEach()`遍历键集。

## Java `HashMap`迭代值

我们可能只想对`HashMap`的值进行迭代。

`com/zetcode/HashMapValues.java`

```java
package com.zetcode;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class HashMapValues {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        Collection<String> vals = capitals.values();

        vals.forEach(System.out::println);
    }
}

```

该示例迭代`HashMap`的值。

```java
Collection<String> vals = capitals.values();

```

`HashMap`的值通过`values()`方法检索。

```java
vals.forEach(System.out::println);

```

我们使用`forEach()`遍历集合。

## `HashMap`过滤

可以使用 Java 流 API 的`filter()`方法过滤`HashMap`。

`com/zetcode/HashMapFilter.java`

```java
package com.zetcode;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class HashMapFilter {

    public static void main(String[] args) {

        Map<String, String> capitals = new HashMap<>();

        capitals.put("svk", "Bratislava");
        capitals.put("ger", "Berlin");
        capitals.put("hun", "Budapest");
        capitals.put("czk", "Prague");
        capitals.put("pol", "Warsaw");
        capitals.put("ita", "Rome");

        Map<String, String> filteredCapitals = capitals.entrySet().stream()
                .filter(map ->  map.getValue().length() == 6)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        filteredCapitals.entrySet().forEach(System.out::println);
    }
}

```

在示例中，我们将映射过滤为仅包含值大小等于 6 的对。

```java
czk=Prague
ger=Berlin
pol=Warsaw

```

这是输出。

## 其他语言的 Java `HashMap`等效项

Ruby 具有哈希，Perl 具有哈希，PHP 具有数组，Python 具有字典，C# 具有字典，JavaScript 具有映射。

`ruby_hash.rb`

```java
#!/usr/bin/ruby

stones = { 1 => "garnet", 2 => "topaz",
           3 => "opal", 4 => "amethyst"
         }

stones.each { |k, v| puts "Key: #{k}, Value: #{v}" }

```

这是 Ruby 中的哈希。

`perl_hash.py`

```java
#!/usr/bin/perl

my %stones = ( 1 => "garnet", 2 => "topaz",
           3 => "opal", 4 => "amethyst" );

while ( my ($k, $v) = each %stones ) {
    print "$k: $v\n";
}

```

这是一个 Perl 哈希。

`php_array.php`

```java
<?php

$stones = [
    1 => "garnet",
    2 => "topaz",
    3 => "opal",
    4 => "amethyst"
];

foreach ($stones as $key => $value) {
    echo "$key: $value\n";
}

?>

```

这是一个 PHP 数组。

`python_dictionary.py`

```java
#!/usr/bin/python

stones = { 1 : "garnet",
           2 : "topaz",
           3 : "opal",
           4 : "amethyst" }

for key, value in stones.items():

    print("{}: {}".format(key, value))

```

这是 Python 字典。

`csharp_dictionary.cs`

```java
using System;
using System.Collections.Generic;

public class DictionaryExample {

    static void Main() {

        Dictionary<int, string> stones = new Dictionary<int, string> {

            { 1, "garnet" },
            { 2, "topaz" },
            { 3, "opal" },
            { 4, "amethyst" },
        };

        Console.WriteLine("Keys and values of the dictionary:");

        foreach(KeyValuePair<int, string> kvp in stones) {

            Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
        }
    }
}

```

这是 C# 词典。

`javascript_map.js`

```java
var stones = new Map();

stones.set(1, 'garnet');
stones.set(2, 'topaz');
stones.set(3, 'opal');
stones.set(4, 'amethyst');

stones.forEach(function(value, key) {
  console.log(key + ': ' + value);
});

```

这是一个 JavaScript 映射。

在本教程中，我们介绍了 Java `HashMap`集合。 您可能也对相关教程感兴趣： [Java 中的`HashMap`迭代](/java/hashmapiterate/)， [Java `ArrayList`教程](/articles/javaarraylist/)， [Java `HashSet`教程](/java/hashset)， [Java 静态关键字](/java/statickeyword/) 和 [Java 教程](/lang/java/)。

列出[所有 Java 教程](/all/#java)。