HashMap基于哈希算法工作,根据Java文档HashMap具有以下四个构造函数,
建设者 | 描述 |
---|---|
HashMap () | 构造一个空的 具有默认初始容量(16)和默认加载因子(0.75)的 HashMap 。 |
HashMap (int initialCapacity) | 构造一个空的 具有指定初始容量和默认加载因子(0.75)的 HashMap 。 |
HashMap (int initialCapacity, | 构造一个空的 具有指定初始容量和负载因子的 HashMap 。 |
HashMap ( Map <? extends K ,? extends V > m) | 构造一个新的 HashMap 具有与指定相同的映射 Map 。 |
让我们编写一个简单的Java程序,以检查Map在内部如何工作
- 创建一个简单的Map并为其添加一个键和值
public static void main(String[] args) {Map<Integer, String> map = new HashMap<>();map.put(1, "Java");}
我们刚刚创建了简单映射,将键作为整数,将值作为字符串,并添加了“ 1”作为键和“ Java”作为值。 通过使用eclipse调试功能,我们可以查看地图中的内容
它创建了16个块(0-15),并插入了第一个块,其键为整数“ 1”,值为字符串“ Java”。 请选中红色框,其余所有都用null初始化的框。
2.将第二个键和值添加到同一地图
public static void main(String[] args) {Map<Integer, String> map = new HashMap<>();map.put(1, "Java");map.put(2, "Angular");}
让我们再次在Eclipse调试中查看地图
现在,地图包含了两个键(1,2)和两个值(“ Java”,“ Angular”),但这些键分别分别精确地添加到了第一个块和第二个块,为什么?
因为我们知道Map是基于哈希算法工作的,所以每当我们插入要映射的键时,它都会根据hashCode()的值调用Object#hashcode()方法,它将把键插入该块中。
在上述情况下,Integer类使用其原始int值覆盖hashCode,这就是为什么(1,java)存储在第一个块中,而(2,Angular)存储在第二个块中的原因。
3.让我们对自己的班级做同样的实验
创建一个简单的Employee类,如下所示
private static class Employee{
int id;
String name;Employee(int id, String name){
this.id = id;
this.name = name;
}
}
使用此类作为地图的键并进行相同的检查
public static void main(String[] args) {
Map<Employee, String> map = new HashMap<>(10);
map.put(new Employee(1, "Ramesh"), "Java");
map.put(new Employee(2, "Sathish"), "Angular");
}
我们添加了两个键作为Employee对象,将Values作为字符串添加,让我们看看这次存储在哪个块中的键
这次,它存储在第8个块和第14个块中(为什么?由于Employee对象的hashCode而给出简单答案),以确认这一点,让Employee的hashCode()重写为常数值并检查映射。 如果我们的分析正确,则必须将所有密钥存储在同一块中。
相应地更新Employee类
private static class Employee{
int id;
String name;
Employee(int id, String name){
this.id = id;
this.name = name;
}
@Override
public int hashCode() {
return 10;
}
}
我们不需要对地图进行任何更改,现在让我们看看密钥的存储位置
是的,只有第10个块充满了两个对象,为什么? 因为两个雇员对象都返回相同的hashCode(即10)。 但是,Map如何识别这两个对象不是重复的? 我们从内部知道Map#Key是entrySet(java.util.Set),它调用equals方法来验证密钥是否重复。
同时从Map中检索值时,首先将检查给定键的hashCode并基于该哈希码将转到该块,在找到该块之后,它将调用equals()以获取确切值。
因此,完全不建议将hashCode()重写为constant 。 当我们覆盖hashCode()时,我们也不应忘记覆盖equals()方法 (即hashCode()/ equals()合约)。
翻译自: https://www.javacodegeeks.com/2017/11/java-hashmap-detail-explanation.html