集合框架-HashMap&HashSet&LinkedHshMap
一、HashMap的底层实现
HashMap底层是基于数组和链表实现的。其中最重要的参数:容量和负载因子。
容量的默认大小事16,负载因子是0.75,当HashMap的size>16*0.75的时候就会发生库容(容量和负载因子都可以自由调整)
Hashmap实现了Map接口,允许放入null元素,出了该类未实现同步外,其余和HashTable大致相同,跟TreeMap不同,该容器不保证冤死顺序,根据需要该容器可能对元素重新哈希,元素的顺序也会被重新打散,因此不同时间迭代同一个HashMap的顺序可能会不同。
二、HashMap的put(key,value)方法
首先会将传入的可以、做hash运算计算出hashCode,然后根据数组长度取模计算出在数组中的index下表
由于在计算机中位运算比取模运算效率高,所以HashMsap规定数组的长度为2n。这样用2n-1做位运算与取模效果一致,并且效率要高出许多
由于数组的长度有限,所以难免出现不同放入key通过运算得到的index相同,这种情况可以利用链表来解决,HashMap会在table[index]出形成链表,采用头插法将数据插入链表中
三、HashMap的get(key)fangfa
get和put类似,也是讲传入的可以计算出index,如果该位置上是一个链表就需要比那里整个链表,通过key.equals(k)来找到对应的元素。
遍历方式:
第一种
Iterator<Map.Entry<String, Integer>> entryIterator=map.entrySet().iterator();
while(entryIterator.hasNext()){
Map.Entry<String,Integer> next=entryIterator.next();
System.err.println("key="+next.getKey()+"value="+next.getValue());
}
第二种
Iterator iterator=map.keySet().iterator();
while(iterator.hasNext()){
String key=iterator.next();
System.err.println("key="+key+"value="+map.get(key));
}
第三种
map.forEach((key,value)->{
System.err.println("key="+key+"value="+value);
});
第一种可以把key value同时取出,第二种还得需要通过key去一次value,效率较低,第三种需要JDK1.8以上,通过外层遍历table,内层遍历链表或红黑树。
四、为什么多线程场景下不推荐使用HashMap
在并发环境下使用HashMap容易出现死循环。并发场景下发生扩容,调用resize()方法里的rehash()时,容易出现环形链表。这样当获取一个不存在的key时,计算出的index正好是环形链表的下标时就会出现死循环
所以,HashMap只能在单线程中使用,并且尽量的预设容量,尽可能的减少扩容发
在JDK1.8中对HashMap进行了优化:当hash碰撞之后写入链表的长度超过阈值(默认为8),链表将会转换成红黑树。假设hash冲突非常严重,一个数组后面接了很长的链表,此时查询的时间复杂度就是O(n)。如果是红黑树,时间复杂度就是O(logn)。大大提高了查询的效率。多线程场景下推荐使用ConcurrentHashMap。
五、HashSet的底层实现
HashSet是对HashMap的简单包装,对HashSet的函数调用都会转换成合适的HashMap方法,因此HashSet的实现非常简单。
成员变量
首先了解下HashSet的成员变量
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
发现主要有两个变量:
map:用于存放最终数据
PRESENT:是所有写入map的value值
构造函数
public HashSet() {
map = new HashMap<>();
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
构造函数很简单,利用了HashMap初始化了map
add
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
比较关键的就是这个add()方法。可以看出他是将存放的对象当做了HashMap的键,value都是相同的PRESENT.由于HashMap的key是不能重复的,所以每当有重复的值写入到HashSet中只能存放不重复的元素
集合框架-HashMap&HashSet&LinkedHshMap的更多相关文章
- Java集合框架之HashSet浅析
Java集合框架之HashSet浅析 一.HashSet综述: 1.1HashSet简介 位于java.util包下的HashSet是Java集合框架的重要成员,它在jdk1.8中定义如下: publ ...
- Java自学-集合框架 HashMap
Java集合框架 HashMap 示例 1 : HashMap的键值对 HashMap储存数据的方式是-- 键值对 package collection; import java.util.HashM ...
- java - day011 - 集合, ArrayList HashMap,HashSet, Iterator 接口, for-each 循环格式
集合 ArrayList 丑数: 能被3,5,7整除多次, ArrayList list 接口 | - ArrayList | - Linked ...
- java集合框架之HashSet
参考http://how2j.cn/k/collection/collection-hashset/364.html#nowhere 元素不能重复 Set中的元素,不能重复重复判断标准是: 首先看ha ...
- java集合框架(hashSet自定义元素是否相同,重写hashCode和equals方法)
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不一致,元素不可以重复 * (通过哈希值来判断是否是同一个对象) * ----HashSet:底层数据结构是哈希表, * 保证 ...
- 集合框架—HashMap
HashMap提供了三个构造函数: HashMap():构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap. HashMap(int ini ...
- [javaSE] 集合框架(HashSet)
Set:元素是无序,不可重复的 HaseSet:底层数据结构是哈希表 定义一个类Demo 获取Demo对象,system.out.println(demo),打印demo对象,Demo@xxxxxx ...
- java集合框架 hashMap 简单使用
参考文章:http://blog.csdn.net/itm_hadf/article/details/7497462 通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷. 加载因 ...
- Java自学-集合框架 HashMap和Hashtable的区别
HashMap和Hashtable之间的区别 步骤 1 : HashMap和Hashtable的区别 HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式 区别1: Hash ...
随机推荐
- BUUCTF-Misc-No.3
比赛信息 比赛地址:Buuctf靶场 内心os(蛮重要的) 我只想出手把手教程,希望大家能学会然后自己也成为ctf大佬,再来带带我QWQ 文件中的秘密 | SOLVED | 打开文件,winhex照妖 ...
- dotNetCore阅读源码-CreateDefaultBuilder及ConfigureWebHostDefaults内部
版本:DotNetCore 3.1 CreateDefaultBuilder内部源码: public static IHostBuilder CreateDefaultBuilder(string[] ...
- Linux多任务编程之一:任务、进程、线程(转)
来源:CSDN 作者:王文松 转自:Linux公社 Linux下多任务介绍 首先,先简单的介绍一下什么叫多任务系统?任务.进程.线程分别是什么?它们之间的区别是什么?,从而可以宏观的了解一下这三者 ...
- Jmeter系列(41)- Jmeter + Ant +Jenkins 持续集成
如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html Window 环境准备 安装 ant: ...
- day82 序列化器-Serializer
目录 一.序列化器的基本功能 二.定义序列化器 三.创建Serializers对象 四.序列化器的使用 1 序列化 2 反序列化 2.1 数据验证(类比forms组件) 2.2 数据保存 一.序列化器 ...
- 记一次开发CefSharp做浏览器时Shopify绑定不上Paypal问题
问题:CefSharp做浏览器时Shopify绑定不上Paypal. shopify绑定Paypal的流程大概是如下图所示 步骤1 步骤2 步骤3 步骤4 出现问题大概是在绑定最后一步,并没有如愿的返 ...
- 数据可视化之分析篇(九)PowerBI数据分析实践第三弹 | 趋势分析法
https://zhuanlan.zhihu.com/p/133484654 以财务报表分析为例,介绍通用的分析方法论,整体架构如下图所示: (点击查看大图) 我会围绕这五种不同的方法论,逐步阐述他们 ...
- 对掌机游戏Pokemon的一部分系统的拆解流程图
整体系统拆解 POKEMON系统拆解 属性.技能.进化形态 属性提升系统 种族值说明: 所有Pokemon都拥有自己的种族的种族值,且固定(例如:小火龙:309, 皮卡丘: 320) 种族值是各项属性 ...
- Spring Bean的生命周期 ---附详细流程图及测试代码
一.生命周期流程图: Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点 假设一个Bean实现了所有的接口,大的概况一下Be ...
- CocosCreator之分层管理的ListView
前言 进入公众号回复listview即可获得demo的git地址. 之前写的一篇文章<Creator之ScrollView那些事>中提到了官方Demo中提供的ListViewCtl,只是实 ...