Java基础一篇过(五)Map这篇就够了
文章更新时间:2020/03/03
一、Map介绍
Map是Java的一个接口,没有继承,以Key--Value的形式来储存元素信息,常用到的有3个子类实现:
- HashMap
- 底层数据结构是散列桶(数组和链表和红黑树)。线程不安全【JDK1.8版本】
- TreeMap
- 底层数据结构是红黑树。线程不安全
- HashTable
- 底层数据结构是散列桶(数组和单链表)。线程安全
下面就这3个常用子类进行分析学习。
二、HashMap
HashMap位于java.util包下
底层实现:散列桶(数组、链表和红黑树)
特点:
- 数据无序(增删改查访问都很快)
- 键和值均允许为null
- 非同步底层由散列表(哈希表)实现
- 需要设置好初始容量和装载因子才可以发挥最大性能
属性

内部类

底层数据结构说明

主要方法解析
get()
- 找键的hash地址 :使用键对象的hashcode找到bucket(桶)位置
- 比较键 : 调用keys.equals()方法找到链表中正确的节点,获取值

put()
- 对Key求Hash值,然后再计算下标
- 如果没有碰撞,直接放入桶中(碰撞的意思是计算得到的Hash值相同,需要放到同一个bucket中)
- 如果碰撞了,以链表的方式链接到后面
- 如果链表长度超过阀值( TREEIFY THRESHOLD==8),就把链表转成红黑树,链表长度低于6,就把红黑树转回链表
- 如果节点已经存在就替换旧值
- 如果桶满了(容量16*加载因子0.75),就需要 resize(扩容2倍后重排)
PS : 桶即HashMap初始化时的(Node[] table=new Node[16])数组。
小结
- 结构:数组内装链表或者红黑树
- 当线性链表深度大于8时,查询效率会降低,所以1.8以后加入了红黑树,当链表深度超过转换阈值8时,将链表转换为红黑树以提升查询效率
- 外层数组容量达到0.75时会进行扩容,每次扩容后的容量为原来的2倍
- 在调用resize()方法时会对原数据进行rehash,此时结构重排,也就出现了红黑树向链表转换的阈值6
三、TreeMap
TreeMap位于java.util包下
底层实现:红黑树(平衡的二叉搜索树)
特点:
- 数据有序
- 比HashMap多实现了了NavigableMap接口,使得键有序
- 能根据比较器对键做大小排序
- 非同步,线程不安全
红黑树的特性:
- (1)树的节点只有红与黑两种颜色。
- (2)红色节点的子节点必定是黑色的。
- (3)根节点为黑色的。
- (4)叶子节点(NIL节点,即空节点)为黑色的。
- (5)从任意节点出发,到其后继的叶子节点的路径中,黑色节点的数目相同。
PS:以上5大特性使得红黑树的根节点到叶子节点的最长路径不会大于最短路径的2倍。
红黑树动态图解可戳这里~
NavigableMap接口
TreeMap之所以能够实现有序的数据结构,主要原因就是实现了NavigableMap接口,下面借用大佬的一张图来清晰的展示NavigableMap接口的特点:

TreeMap数据结构
TreeMap储存键值对的单位为一个一个的Entey()对象 ,Entry作为TreeMap存储的结点,包括键、值、父结点、左孩子、右孩子、颜色。源码如下所示:
static final class Entry<K, V> implements Map.Entry<K, V> {
K key;//节点的键
V value;//节点的值
TreeMap.Entry<K, V> left;//左子节点(左孩子)
TreeMap.Entry<K, V> right;//右子节点(右孩子)
TreeMap.Entry<K, V> parent;//父节点
boolean color = BLACK;//节点颜色:默认黑色
}
构造方法
TreeMap有四种构造函数,,由不同的入参指定:
//比较器
private final Comparator<? super K> comparator; //1.键自然顺序
public TreeMap() {
comparator = null;
} //2.根据给定的比较器进行排序
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
} //3.构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序进行排序
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
// putAll()将m中的所有元素添加到TreeMap中
putAll(m);
} //4.构造一个与指定有序映射具有相同映射关系和相同排序顺序的新的树映射
public TreeMap(SortedMap<K, ? extends V> m) {
comparator = m.comparator();
try {
// buildFromSorted将m中的所有元素按同样的排序方式添加到TreeMap中
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (Exception e) {
}
}
主要方法解析
put()
- (1)获取TreeMap的比较器(Comparator)
- (2)根据比较器规则比较插入的节点,相等时则覆盖,不等时准备下一步工作【没定义比较器时按默认的方式排序】
- (3)比较树内已存在的节点,并进行节点插入
- (4)插入节点后检查并修复树【对增节点后的树进行左旋,右旋,变色等操作】,保持平衡
PS:使用TreeMap时,键必须实现Comparable接口或者构造时传入比较器,若键中存在null值得情况,可以在自定义的比较器中设置null值的处理情况【默认情况下TreeMap是不支持传入null键的】
get()
- 判断TreeMap存不存在传入的自定应比较器
- 若存在比较器时,按比较器的规则进行节点查找
- 若没有自定义比较器时,则按普通二叉排序树的查找规则来搜索树节点
remove()
- (1)根据key找到待删除的结点
- (2)删除节点,并修复红黑树
与HashMap的异同
TreeMap和HashMap的相同点
- 两者均是线程不安全的。
- 两者插入节点时,key重复均覆盖旧值。
TreeMap和HashMap的不同点
- HashMap的实现基于数组和链表,而TreeMap的实现基于红黑树。
- HashMap的key是无序的,TreeMap的key是有序的。
- TreeMap要求key必须实现Comparable接口,或者初始化时传入Comparator比较器。
- HashMap增删改查操作的时间复杂度为O(1),TreeMap增删改查操作的时间复杂度为O(log(n))。
- HashMap允许null值,TreeMap中默认的排序算法中put操作不允许null键,但是值(value)允许为null;若传入自定义比较器,可以手动处理null键的情况。
小结
- TreeMap的查询、插入、删除效率均没有HashMap高,一般只有要对key排序时才使用TreeMap
- TreeMap的key不能为null,而HashMap的key可以为null。
- 非线程安全,若须实现同步可:SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));
四、HashTable
HashMap位于java.util包下
底层实现:散列桶(数组和单链表)
特点:
- 数据无序
- 键和值均不允许为null
- 线程安全
具体结构与HashMap相类似,简单归纳如下:
属性
//HashTable的数组【实质是一个Enrty数组,数组的默认长度:11】
private transient Entry<?,?>[] table; //HashTable条目数总量
private transient int count; //下次扩容量【每次扩容大小:2倍旧长度+1】
private int threshold; //负载因子【默认:0.75】
private float loadFactor; //修改次数
private transient int modCount = 0;
主要方法解析
put()
- (1)判断value不可为空
- (2)若key已经在table中存在,通过for循环,查找符合条件的key,用新值覆盖旧值,并返回旧值
- (3)若key不存在则进行新增操作:
- (modCount)修改次数+1,判断HashTable是否需要扩容
- 根据hash算法得到索引位置
- 在指定位置插入新的Entry对象
- HashTable的(count)条目数 +1
get()
- 用与put方法内同样的hash算法计算出key对应的索引下标,去外层的Entry数组内获取对应的value
remove()
- (1)用与put方法内同样的hash算法计算出key对应的索引下标
- (2)删除节点,并修复链表
五、总结
HashMap
- 数据无序
- 底层实现是散列桶(数组和链表和红黑树)
- 默认初始化容量是16,每次容量达到外层Entry数组的0.75倍以后就会扩容2倍
- 键和值均允许为null
- 非同步,线程不安全
TreeMap
- 数据有序
- 比HashMap多实现了了NavigableMap接口,使得键有序
- 非同步,线程不安全
HashTable
- 数据无序
- 键和值均不允许为null
- 同步,线程安全
一句话小结:增删改查多用HashMap,需要排序的Map场景用TreeMap,同步场景用HashTable。
参考资料:
Java基础一篇过(五)Map这篇就够了的更多相关文章
- Java基础知识常见面试题汇总第一篇
[Java面试题系列]:Java基础知识常见面试题汇总 第一篇 文中面试题从茫茫网海中精心筛选,如有错误,欢迎指正! 1.前言 参加过社招的同学都了解,进入一家公司面试开发岗位时,填写完个人信息后 ...
- JAVA基础第四章-集合框架Collection篇
业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...
- 【Java面试题系列】:Java基础知识常见面试题汇总 第一篇
文中面试题从茫茫网海中精心筛选,如有错误,欢迎指正! 1.前言 参加过社招的同学都了解,进入一家公司面试开发岗位时,填写完个人信息后,一般都会让先做一份笔试题,然后公司会根据笔试题的回答结果,确定 ...
- Java基础复习笔记系列 五 常用类
Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...
- JAVA基础学习day16--集合三-Map、HashMap,TreeMap与常用API
一.Map简述 1.1.简述 public interface Map<K,V> 类型参数: K - 此映射所维护的键的类型 key V - 映射值的类型 value 该集合提供键--值的 ...
- Java基础笔试练习(五)
1.以下关于Integer与int的区别错误的是? A.int是java提供的8种原始数据类型之一 B.Integer是java为int提供的封装类 C.int的默认值为0 D.Integer的默认值 ...
- JAVA基础知识总结:五
一.初步认识数组 1.理解数组 数组是用来存储相兼容数据类型的定长的容器 特点: a.只能存放相兼容数据类型,不能存放多种数据类型 b.可以存放基本数据类型和引用数据类型 c.数组是定长的,一旦被初始 ...
- java基础36 双例集合Map下的HashMap和TreeMap集合
单例集合体系: ---------| collection 单例集合的根接口--------------| List 如果实现了list接口的集合类,具备的特点:有序,可重复 注:集合 ...
- java基础35 双例集合Map及其常用方法
单例集合体系: ---------| collection 单例集合的根接口--------------| List 如果实现了list接口的集合类,具备的特点:有序,可重复 注:集合 ...
- java基础之集合:List Set Map的概述以及使用场景
本文的整体思路以及部分文字来源:来源一 和 来源二 Java集合类的基本概念: 首先大家要明白集合为什么会出现: 在编程中,常常需要集中存放多个数据.从传统意义上讲,数组是我们的一个很好的选择,前提是 ...
随机推荐
- 黑马新版PYTHON教学课程(全)资料加视频完整版百度网盘资料
黑马新版PYTHON教学课程(全)资料加视频完整版 无加密,适合0基础人群.基础班+就业班.不用解压在线看 百度网盘地址一 淘宝店地址二
- 【趣味设计模式系列】之【代理模式3--Cglib动态代理源码解析】
1. 图解 上图主要描述了Cglib动态代理的主要执行过程,下面做详细分析,以下源码使用的Cglib版本为3.2.12. 2. Enhancer源码分析 public Object create() ...
- 区块链入门到实战(23)之以太坊(Ethereum) – 虚拟机架构
以太坊(Ethereum)网络中,定义了一组通用协议用于支持智能合约的运行,其核心便是以太坊(Ethereum)虚拟机. 下图解释了该架构: 开发人员使用Solidity等开发语言开发智能合约 源程序 ...
- Fiddler或Charles文件转换为Jmeter可执行脚本
解决脚本录制问题,可以将Fiddler或Charles转换成对应的Jmeter脚本,实现部分内容的参数化配置,通过修改部分参数或参数化可以对http协议的接口进行自动化测试或简单的压力测试 GitHu ...
- Laravel Reponse 响应客户端
Laravel Response 响应客户端 本篇文章逻辑较长,只说明和响应生命周期相关的必要代码. 本文主要内容顺序为: 1.执行上文管道中的then方法指定的闭包,路由的分发 2.在路由器中(Ro ...
- 拾色器,可以取出电脑屏幕的任何颜色,ui以及程序员前端等常用软件,文件很小,300K
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985,转载请说明出处. 今天给大家介绍一个小软件,挺实用的,叫做拾色器. 用途:取出电脑屏幕的任意颜色,当你 ...
- android开发之java代码中如何获取到当前时间。详情代码带注释。
/** *获取当前时间 * @return */ public String getTime(){ Date date= new Date();//创建一个时间对象,获取到当前的时间 SimpleDa ...
- UGUI核心元素、基本控件、复合控件和高级控件
UGUI的核心元素: Anchor(锚点):每个控件都有一个Anchor属性,控件的4个顶点,分别与Anchor的4个点保持不变的距离,不受屏幕分辨率变化的影响. 系统默认设置控件的Anchor位置在 ...
- AOP理论
目录 AOP理论 什么是AOP 那Spring AOP,AspectJ又是啥呢? 为什么说AOP是OOP的补充和完善呢? 应用场景举例 AOP的优点 AOP的术语整理 AOP理论 什么是AOP AOP ...
- 绝世好题(线性dp)
给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len). Input 输入文件共2行. 第一行包括一个整数n. 第二行包括n个 ...