特性:

HashMap 与 Hashtable 的分析:

1):HashMap简介

  1、底层数组+链表实现,可以存储null键和null值,线程不安全

  2、HashMap 不是线程安全的

  3、HashMap 是 map 接口的子类。

  4、HashMap 允许null key 和 null value。

  5、允许 key 重复,但是会把之前的覆盖。

  6、HashMap 是 Hashtable 的轻量级实现(非线程安全的实现),他们都完成了Map接口。

  7、HashMap 是 reHash算法,而 HashTable 是 hash算法。两者差不多

  8、HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsvalue 和 containsKey。因为contains方法容易让人引起误解。

HashMap结构图:

简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(如果不同的key映射到了数组的同一位置处,就将其放入单链表中)。

如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,

仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

几个比较重要的字段:

//实际存储的key-value键值对的个数
transient int size;
//阈值,当table == {}时,该值为初始容量(初始容量默认为16);当table被填充了,也就是为table分配内存空间后,threshold一般为 capacity*loadFactory。
//HashMap在进行扩容时需要参考threshold,后面会详细谈到
int threshold;
//负载因子,代表了table的填充度有多少,默认是0.75
final float loadFactor;
//用于快速失败,由于HashMap非线程安全,在对HashMap进行迭代时,如果期间其他线程的参与导致HashMap的结构发生变化了(比如put,remove等操作),需要抛出异常ConcurrentModificationException
transient int modCount;

HashMap有4个构造器,其他构造器如果用户没有传入 initialCapacity 和 loadFactor这两个参数,会使用默认值 initialCapacity默认为16,loadFactory默认为0.75

我们看下其中一个:

public HashMap(int initialCapacity, float loadFactor) {
     //此处对传入的初始容量进行校验,最大不能超过MAXIMUM_CAPACITY = 1<<30(230)
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor); this.loadFactor = loadFactor;
threshold = initialCapacity;
     
init();//init方法在HashMap中没有实际实现,不过在其子类如 linkedHashMap中就会有对应实现
}

从上面这段代码我们可以看出,在常规构造器中,没有为数组 table 分配内存空间(有一个入参为指定Map的构造器例外),而是在执行 put 操作的时候才真正构建 table 数组 OK。

接下来我们来看看put操作的实现吧。

public V put(K key, V value) {
//如果table数组为空数组{},进行数组填充(为table分配实际内存空间),入参为threshold,此时threshold为initialCapacity 默认是1<<4(24=16)
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
//如果key为null,存储位置为table[0]或table[0]的冲突链上
if (key == null)
return putForNullKey(value);
int hash = hash(key);//对key的hashcode进一步计算,确保散列均匀
int i = indexFor(hash, table.length);//获取在table中的实际位置
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
//如果该对应数据已存在,执行覆盖操作。用新value替换旧value,并返回旧value
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;//保证并发访问时,若HashMap内部结构发生变化,快速响应失败
addEntry(hash, key, value, i);//新增一个entry
return null;
}

2):HashTable介绍

  1、底层数组+链表实现.

  2、无论 key 还是 value 都不能为 null。

  3、线程安全:实现线程安全的方式是在修改数据时锁住整个HashTable,效率低。

  4、Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题。

  5、hashtable 采用 hash 算法。

 

最新文章

  1. gitHub使用入门和github for windows的安装教程
  2. 【repost】JS原型与原型链终极详解
  3. CSS文件开头到底声明@charset &quot;utf-8&quot;
  4. youtube视频批量下载
  5. android短信的接收和发送处理
  6. bzoj 1060 [ZJOI2007]时态同步(树形DP)
  7. 【POJ3294】 Life Forms (后缀数组+二分)
  8. C语言深度解剖读书笔记(6.函数的核心)
  9. CentOS 6.5 安装MySQL5.7 RPM
  10. [Micropython][ESP8266] TPYBoard V202 之MQTT协议接入OneNET云平台
  11. tomcat-theory
  12. 网站开发进阶(四十三)html中,路径前加“/” 与不加“/”的区别
  13. RadioButton监听事件
  14. Flutter windows环境安装 + 模拟设备 + 项目运行
  15. Python——Menu控件
  16. TensorFire:WEB端的高性能神经网络框架
  17. Confluence 6 如何保持我空间的整洁
  18. 彻底卸载Oracle database 12c教程
  19. 课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 0、学习目标
  20. Matrix_QP(A_2SeqSum)

热门文章

  1. SpringBoot处理url中的参数的注解
  2. MySQL中有关icp mrr和bka的特性
  3. 0x02 MySQL SQL基本语句
  4. 安装mysql以及修改初始密码
  5. 免费 SSL 安全证书
  6. 对JAVA的集合的理解
  7. asp.net Cookie 用户登陆时记住我
  8. UI控件之UITabBarController
  9. Java 集合系列13之 TreeMap详细介绍(源码解析)和使用示例
  10. &lt;script&gt;放在head内和body内有什么区别