JAVA面试题(一):HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap的区别

**Map

                     有序性	     线程安全性	              备注**

1.HashMap 无序 不安全
2.Hashtable 无序 安全 不允许null
3.LinkedHashMap 有序 不安全 根据插入/访问顺序排序,有序的
4.ConcurrentHashMap 无序 安全 线程安全的HashMap

Map的两种取值方式

:keySet、entrySet
  keySet
    先获取所有键的集合, 再根据键获取对应的值.
  entrySet
    先获取map中的键值关系封装成一个个的entry对象, 存储到一个Set集合中,再迭代这个Set集合, 根据entry获取对应的key和value。
  向集合中存储自定义对象 .

HashMap : 内部结构是哈希表,不是同步的。允许null作为键,null作为值。
TreeMap : 内部结构是二叉树,不是同步的。可以对Map集合中的键进行排序。
  
JAVA面试题(一):HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap的区别_第1张图片

HashMap****的数据结构

哈希表是由数组+链表组成的,(注意,这是jdk1.8之前的)数组的默认长度为16。

为什么是数组+链表?

数组对于数据的访问如查找和读取非常方便,链表对于数据插入非常方便。

链表可以解决hash值冲突(即对于不同的key值可能会得到相同的hash值)

数组里每个元素存储的是一个链表的头结点。而组成链表的结点其实就是hashmap内部定义的一个类:Entity

Entity包含三个元素:key,value和指向下一个Entity的next。

HashMap的存取

HashMap的存储–put : null key总是存放在Entry[]数组的第一个元素

元素需要存储在数组中的位置。先判断该位置上有没有存有Entity,没有的话就创建一个Entity对象,新的Entity插入(put)的位置永远是在链表的最前面。

HashMap的读取–get : 先定位到数组元素,再遍历该元素处的链表.

覆盖了equals方法之后一定要覆盖hashCode方法,原因很简单,比如,String a = new String(“abc”); String b = new String(“abc”); 如果不覆盖hashCode的话,那么a和b的hashCode就会不同。

HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。

Hashtable 概述

也是一个散列表,它存储的内容是键值对(key-value)映射。
  Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口
  Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。
  Hashtable中的映射不是有序的。
  Hashtable继承于Dictionary类,实现了Map接口。Map是"key-value键值对"接口,Dictionary是声明了操作"键值对"函数接口的抽象类。

hashtable与hashmap区别

(1)继承的父类不同
    Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。
  (2)线程安全性不同
    Hashtable 中的方法是Synchronize的,而HashMap中的方法在缺省情况下是非Synchronize的。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步,但使用HashMap时就必须要自己增加同步处理。
  (3)是否提供contains方法
    HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因为contains方法容易让人引起误解。
    Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。
  (4)key和value是否允许null值
    其中key和value都是对象,并且不能包含重复key,但可以包含重复的value。
    Hashtable中,key和value都不允许出现null值。
    HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
  (5)两个遍历方式的内部实现上不同
    Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
  (6)hash值不同
    哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
  (7)内部实现使用的数组初始化和扩容方式不同
    Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。
    HashMap中hash数组的默认大小是16,而且一定是2的指数。

LinkedHashMap

HashMap 是一个无序的 Map,因为每次根据 key 的 hashcode 映射到Entry数组上,所以遍历出来的顺序并不是写入的顺序。
因此 JDK 推出一个基于 HashMap 但具有顺序的 LinkedHashMap 来解决有排序需求的场景。
LinkedHashMap继承于HashMap 所以一些 HashMap 存在的问题 LinkedHashMap也会存在,比如不支持并发等
实现
hashcode实现唯一,双向链表实现有序
LinkedHashMap 的排序方式有两种:
根据写入顺序排序。
根据访问顺序排序。
顺序访问

每次 get 都会将访问的值移动到链表末尾,这样重复操作就能得到一个按照访问顺序排序的链表。
JAVA面试题(一):HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap的区别_第2张图片

同步方法:ConcurrentHashMap

Hashtable的put和get方法均为synchronized的是线程安全的。

将HashMap默认划分为了16个Segment,减少了锁的争用。

写时加锁读时不加锁减少了锁的持有时间。

volatile特性约束变量的值在本地线程副本中修改后会立即同步到主线程中,保证了其他线程的可见性。

value外,其他的属性都是final的,value是volatile类型的,都修饰为final表明不允许在此链表结构的中间或者尾部做添加删除操作,每次只允许操作链表的头部。

你可能感兴趣的:(JAVA面试题(一):HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap的区别)