解决指针碰撞问题:

Java中HashMap是利用“拉链法”处理HashCode的碰撞问题。在调用HashMap的put方法或get方法时,都会首先调用hashcode方法,去查找相关的key,当有冲突时,再调用equals方法。hashMap基于hasing原理,我们通过put和get方法存取对象。当我们将键值对传递给put方法时,他调用键对象的hashCode()方法来计算hashCode,然后找到bucket(哈希桶)位置来存储对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当碰撞发生了,对象将会存储在链表的下一个节点中。hashMap在每个链表节点存储键值对对象。当两个不同的键却有相同的hashCode时,他们会存储在同一个bucket位置的链表中。键对象的equals()来找到键值对。


再散列rehash过程

当哈希表的容量超过默认容量时,必须调整table的大小。当容量已经达到最大可能值时,那么该方法就将容量调整到Integer.MAX_VALUE返回,这时,需要创建一张新表,将原表的映射到新表中。

为什么是不安全的

1、比如put   a,b  两个数值,两个hashcode相同,则会存储时争夺存储位置,HashMap底层是一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入,put方法不是同步的,同时调用了addEntry方法  两个方法都不是同步的。

2、我们知道在HashMap存在扩容的情况,对应的方法为HashMap中的resize方法

这个操作会新生成一个新的容量的数组,然后对原数组的所有键值对重新进行计算和写入新的数组,之后指向新生成的数组。

当多个线程同时检测到总数量超过门限值的时候就会同时调用resize操作,各自生成新的数组并rehash后赋给该map底层的数组table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会有问题。

3、当多个线程同时操作同一个数组位置的时候,也都会先取得现在状态下该位置存储的头结点,然后各自去进行计算操作,之后再把结果写会到该数组位置去,其实写回的时候可能其他的线程已经就把这个位置给修改过了,就会覆盖其他线程的修改


Map的遍历方法:





Map<String, String> map = new HashMap<String, String>();
   map.put("1", "value1");
   map.put("2", "value2");
   map.put("3", "value3");
   
   //第一种:普遍使用,二次取值
   System.out.println("通过Map.keySet遍历key和value:");
   for (String key : map.keySet()) {
    System.out.println("key= "+ key + " and value= " + map.get(key));
   }
   
   //第二种
   System.out.println("通过Map.entrySet使用iterator遍历key和value:");
   Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
   while (it.hasNext()) {
    Map.Entry<String, String> entry = it.next();
    System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
   }
   
   //第三种:推荐,尤其是容量大时
   System.out.println("通过Map.entrySet遍历key和value");
   for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
   } 
  //第四种
   System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
   for (String v : map.values()) {
    System.out.println("value= " + v);
   }
  }