Java Map 与 Go map 对比
Key types in Go map
// headerCopy := map[[]byte][]byte{} // WRONG
headerCopy := map[string][]byte{} // https://blog.golang.org/maps#TOC_5.
ctx.Request.Header.VisitAll(func(key, value []byte) {
headerCopy[string(key)] = value
})
由于遍历 Request.Header 取出来的键值类型为 byte slice,当我尝试以 []byte
作为我要创建的 map 键类型时,编译器阻止了我并提示 Invalid map key type: the comparison operators == and != must be fully defined for key type
。查阅 Go 文档时发现这么一段:
As mentioned earlier, map keys may be of any type that is comparable. The language spec defines this precisely, but in short, comparable types are boolean, numeric, string, pointer, channel, and interface types, and structs or arrays that contain only those types. Notably absent from the list are slices, maps, and functions; these types cannot be compared using ==, and may not be used as map keys.
大意是说:map 键的类型可以是可比较的任何类型。Go 语言规范中明确定义了可比较的类型为:“boolean, numeric, string, pointer, channel, and interface types, and structs or arrays that contain only those types”。其中不包含 slices、maps 和 functions,这些类型都是不能使用 ==
进行比较的,因此不能用作 map 的键。
Key types in Java Map
import java.util.*;
public class A {
public static void main(String[] args) {
Map<List, String> m = new HashMap<>();
List<String> l = new ArrayList<>();
l.add("aaaa");
m.put(l, "1");
System.out.println(m.get(l)); // 1
l.add("aagg");
System.out.println(m.get(l)); // null
l.remove("aagg");
System.out.println(m.get(l)); // 1
List<String> ll = new ArrayList<>();
ll.add("aaaa");
System.out.println(m.get(ll)); // ?
}
}
Java 中 Map 的键类型是以范型进行限定的,这就明确了键的值类型不可能是基本数据类型,必须是引用类型或 null
。
Java 文档中有这么一段描述:
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map. A special case of this prohibition is that it is not permissible for a map to contain itself as a key. While it is permissible for a map to contain itself as a value, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a map.
如果将可变对象用作 Map 的值,则必须非常小心。如果以影响等值比较的方式改变了(作为键的)对象的值,则不会指定映射的行为。我将其理解为:当 Map 键的值对象发生改变时(对象比较使用 .equals()
方法),映射关系不会随之更新。既然不会重新映射,当查找发生改变后的键时,该键所映射的值就为空了。当把键的值对象重新改变为初始的值时,再次查找该键映射的值便可成功找到。
References
- "Go maps in action - The Go Blog".
- "Map (Java SE 14 & JDK 14)".