映射

映射 属于 Java

11 个练习

关于 映射

映射是一种用于存储键值对的数据结构。 它类似于其他编程语言中的字典。 Map 接口定义了你可以对映射执行的操作。

HashMap

Java 有多种不同的 Map 实现。 HashMap 是常用的一种。

// Make an instance
Map<String, Integer> fruitPrices = new HashMap<>();
Note

定义Map变量时,建议把变量声明为Map类型,而不是具体的类型,就像上面这个例子一样。 这样做以后更换Map实现会很方便。

HashMap还有一个复制构造函数。

// Make a copy of a map
Map<String, Integer> copy = new HashMap<>(fruitPrices);

使用 put 向映射中添加条目。

fruitPrices.put("apple", 100);
fruitPrices.put("pear", 80);
// => { "apple" => 100, "pear" => 80 }

每个键只能关联一个值。 用同一个键调用put会更新该键对应的值。

fruitPrices.put("pear", 40);
// => { "apple" => 100, "pear" => 40 }

使用 get 获取某个键对应的值。

fruitPrices.get("apple"); // => 100

使用 containsKey 查看映射中是否包含某个特定的键。

fruitPrices.containsKey("apple");   // => true
fruitPrices.containsKey("orange");  // => false

使用 remove 移除条目。

fruitPrices.put("plum", 90);  // Add plum to map
fruitPrices.remove("plum");   // Removes plum from map

size 方法返回条目的数量。

fruitPrices.size();  // Returns 2

你可以使用 keySet 或 values 方法,分别以 Set 或集合的形式获取 Map 中的键或值。

fruitPrices.keySet();  // Returns "apple" and "pear" in a set
fruitPrices.values();  // Returns 100 and 80, in a Collection

HashMap 使用hashCode和equals

HashMap 使用对象的 hashCode 和 equals 方法,来确定把值存到哪里,以及如何取出某个键对应的值。 因此,它们的返回值在存储和读取之间必须保持不变,否则 HashMap 可能找不到对应的值。

例如,假设我们有下面这个类,它会被用作映射的键:

public class Stock {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (Objects.equals(Stock.class, obj.getClass()) && obj instanceof Stock other) {
            return Objects.equals(name, other.name);
        }
        return false;
    }
}

hashCode和equals依赖于name字段,而该字段可以通过setName改动。 改变hashCode可能会带来意想不到的结果:

Stock stock = new Stock();
stock.setName("Beanies");

Map<Stock, Integer> stockCount = new HashMap<>();
stockCount.put(stock, 80);

stockCount.get(stock); // Returns 80

Stock other = new Stock();
other.setName("Beanies");

stockCount.get(other); // Returns 80 because "other" and "stock" are equal

stock.setName("Choccies");
stockCount.get(stock); // Returns null because hashCode value has changed

stockCount.get(other);  // Also returns null because "other" and "stock" are not equal

stock.setName("Beanies");
stockCount.get(stock); // HashCode restored, so returns 80 again

stockCount.get(other); // Also returns 80 again because "other" and "stock" are back to equal

Map.of 和 Map.copyOf

创建映射的另一种常见方式是使用 Map.of 或 Map.ofEntries。

// Using Map.of
Map<String, Integer> temperatures = Map.of("Mon", 30, "Tue", 28, "Wed", 32);

// or using Map.ofEntries
Map<String, Integer> temperatures2 = Map.ofEntries(
    Map.entry("Mon", 30),
    Map.entry("Tue", 28),
    Map.entry("Wed", 32)
);

与HashMap不同,它们会在一开始就把映射填充好,并且创建之后就变成只读。 Map.copyOf 可以创建映射的只读副本。

Map<String, Integer> readOnlyFruitPrices = Map.copyOf(fruitPrices);

调用put、remove或clear这类方法会导致UnsupportedOperationException。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 映射

练习已锁定

再解锁 1 个练习即可练习 映射