映射是一种用于存储键值对的数据结构。 它类似于其他编程语言中的字典。 Map 接口定义了你可以对映射执行的操作。
Java 有多种不同的 Map 实现。 HashMap 是常用的一种。
// Make an instance
Map<String, Integer> fruitPrices = new HashMap<>();
定义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
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.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。