欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

hashmap hashtable ConcurrentHashMap的区别

程序员文章站 2022-03-03 08:24:23
...

hashcode与equals:

1、HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的

2、如果两个对象equals相等,那么这两个对象的HashCode一定也相同

3、如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写

4、如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置

HashTable

  • 底层数组+链表实现,无论key还是value都不能为null,线程安全
  • 初始size为11,扩容:newsize = oldsize*2+1
  • 计算index的方法  即hash函数:index = (hash & 0x7FFFFFFF) % tab.length

HashMap

  • 底层数组+链表实现,可以存储null键和null值,线程不安全
  • 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
  • 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
  • 插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
  • 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
  • 计算index方法:index = hash & (tab.length – 1)
  • ConcurrentHashMap

  • 底层采用分段的数组+链表实现,线程安全
  • 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
  • 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容

map内部有一个Entry类  所有的键值对关系会被封装成一个Entry对象  可以进行获取遍历

for (Map.Entry<String,Integer> entry:map.entrySet()){
            System.out.println(entry.getKey()+":"+entry.getValue());
        }

将所有的键值对关系放在set集合内 进行遍历