一、Map<K,V>

Java提供了专⻔的集合类⽤来存放这种这种⼀⼀对应的关系,叫做映射对象,即 java.util.Map 接⼝。

类型参数:

K - 此映射所维护的键的类型

V - 映射值的类型

所有已知子接口:

Bindings, ConcurrentMap<K,V>, ConcurrentNavigableMap<K,V>, LogicalMessageContext, MessageContext, NavigableMap<K,V>, SOAPMessageContext, SortedMap<K,V>

所有已知实现类:

AbstractMap, Attributes, AuthProvider, ConcurrentHashMap, ConcurrentSkipListMap, EnumMap, HashMap, Hashtable, IdentityHashMap, LinkedHashMap, PrinterStateReasons, Properties, Provider, RenderingHints, SimpleBindings, TabularDataSupport, TreeMap, UIDefaults, WeakHashMap

1.特点

1).Map集合是一个双列集合,是以key-value的形式表示。
    2).key和value都可以使用泛型,也就意味着可以使用引用数据类型(自定义类)
    3).key值都不允许有重复值。
    4).value值允许有多个重复值。
    5).如果key值出现一致的情况,则value值会被覆盖。
    6).因为key是唯一的,可以通过key找到value值。

 与Collection的区别:

Collection 中的集合,元素是孤⽴存在的(理解为单身),向集合中存储元素采⽤⼀个个元素的⽅式存储。
Map 中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。
Collection 中的集合称为单列集合, Map 中的集合称为双列集合。

2.实现类

1.HashMap<K,V>

HashMap:存储数据采⽤的哈希表结构,元素的存取顺序不能保证⼀致。由于要保证键的唯⼀、不重复,需要重写键的hashCode()⽅法、equals()⽅法。
LinkedHashMap:HashMap下有个⼦类 LinkedHashMap,存储数据采⽤的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序⼀致;通过哈希表结构可以保证的键的唯⼀、不重复,需要重写键的hashCode()⽅法、equals()⽅法。
Tips:Map接⼝中的集合都有两个泛型变量<K, V>,在使⽤时,要为两个泛型变量赋予数据类型。两个泛型变量<K, V>的数据类型可以相同,也可以不同。
特点:与Map特点一样。基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
底层实现:哈希表
底层数据结构:JDK1.7之前 数组+双向链表
JDK1.8之后 数组+双向链表+红黑树
容量问题:

HashMap 的实例有两个参数影响其性能:初始容量 (16)和加载因子(0.75)

容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。

加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。

当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

a.默认初始容量:16
      b.加载因子: 0.75 -> 容量达到百分之75的时候进行扩容
      b.如果元素太少就进行扩容,会造成空间的浪费
      c.如果元素太多进行扩容,则会造成效率低下

常用API 

public V put(K key, V value) :把指定的键与指定的值添加到Map集合中。
public V remove(Object key) :把指定的键 所对应的键值对元素 在Map集合中删除,返
回被删除元素的值。
public V get(Object key) :根据指定的键,在Map集合中获取对应的值。
boolean containsKey(Object key) :判断集合中是否包含指定的键。
import java.util.HashMap;//HashMap 是Map集合接口的实现类 他的常用API
public class HashMapDemo01 {public static void main(String[] args) {HashMap<String,String> hm = new HashMap<>();//添加集合元素hm.put("肖战","王一博");hm.put("小松菜奈","管田将晖");hm.put("Pepper Potts","Tony Stark");hm.put(null,"yeah");//键为空hm.put("hi",null);//值为空//hashmap里允许键或者值为空的情况System.out.println(hm);//{null=yeah, hi=null, Pepper Potts=Tony Stark, 小松菜奈=管田将晖, 肖战=王一博}//输出排序是按hashcode值排序/* boolean containsKey(Object key)如果此映射包含对于指定键的映射关系,则返回 true。*/Object b =  hm.containsKey("肖战");System.out.println(b);//trueObject b1 =  hm.containsKey("小白");System.out.println(b1);//false/* boolean containsValue(Object value)如果此映射将一个或多个键映射到指定值,则返回 true。 */Object b2 = hm.containsValue("管田将晖")  ;System.out.println(b2);//true/* boolean isEmpty()如果此映射 不包含 键-值映射关系,则返回 true。 */Object b3 = hm.isEmpty();System.out.println(b3);//false/* V remove(Object key)从此映射中移除指定键的映射关系(如果存在)。 */Object v1 = hm.remove("小松菜奈");System.out.println(v1);//管田将晖System.out.println(hm);//{null=yeah, hi=null, Pepper Potts=Tony Stark, 肖战=王一博}Object v2 = hm.remove("灰原哀");//不存在的key值System.out.println(v2);//null/*int size()返回此映射中的键-值映射关系数。 */System.out.println(hm.size());//4}
}

Map集合的遍历

1.键找值⽅式:即通过元素中的键,获取键所对应的值

分析步骤:
        1. 获取Map中所有的键,由于键是唯⼀的,所以返回⼀个Set集合存储所有的键。⽅法提示:keyset()
        2. 遍历键的Set集合,得到每⼀个键。
        3. 根据键,获取键所对应的值。⽅法提示:get(K key)

2.Entry键值对对象

我们已经知道, Map 中存放的是两种对象,⼀种称为key(键),⼀种称为value(值),它们在 Map 中是⼀⼀对应关系,这⼀对对象⼜称做 Map 中的⼀个 Entry(项) 。 Entry 将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历 Map 集合时,就可以从每⼀个键值对( Entry )对象中获取对应的键与对应的值。既然Entry表示了⼀对键和值,那么也同样提供了获取对应键和对应值得⽅法:
public K getKey() :获取Entry对象中的键。
public V getValue() :获取Entry对象中的值。
在Map集合中也提供了获取所有Entry对象的⽅法:
public Set<Map.Entry<K,V>> entrySet() :获取到Map集合中所有的键值对对象的集合 (Set集合)。

3.键值对⽅式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。

操作步骤与图解:
1. 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。⽅法提示: entrySet() 。
2. 遍历包含键值对(Entry)对象的Set集合,得到每⼀个键值对(Entry)对象。
3. 通过键值对(Entry)对象,获取Entry对象中的键与值。 ⽅法提示: getkey() getValue() 。

import java.util.*;/*Map 集合的遍历Set<Map.Entry<K,V>> entrySet()返回此映射所包含的映射关系的 Set 视图。Set<K> keySet()返回此映射中所包含的键的 Set 视图。Collection<V> values()返回此映射所包含的值的 Collection 视图。*/
public class HashMapDemo02 {public static void main(String[] args) {Map<Integer,String> map = new HashMap<>();map.put(1,"小白");map.put(2,"小红");map.put(3,"小黑");map.put(4,"小黄");System.out.println(map);//{1=小白, 2=小红, 3=小黑, 4=小黄}/*Set<Map.Entry<K,V>> entrySet()返回此映射所包含的映射关系的 Set 视图。*/Set<Map .Entry<Integer,String>> set =  map.entrySet();for (Map .Entry<Integer,String> m :set) {System.out.println(m);//获取键Integer key = m.getKey();//获取值String value = m.getValue();System.out.println(key + "="+ value);}/*Set<K> keySet()返回此映射中所包含的键的 Set 视图。*/Set<Integer> set1 = map.keySet();//创建迭代器Iterator<Integer> it = set1.iterator();while(it.hasNext()){//获取keyInteger key1 = it.next();String value1 = map.get(key1);//通过键获取值System.out.println(key1+"="+value1);}/** Collection<V> values()返回此映射所包含的值的 Collection 视图。*/Collection<String> col =  map.values();for (String s:col) {String value2 = s;System.out.println(value2);}}
}

LinkedHashMap:

我们知道HashMap保证成对元素唯⼀,并且查询速度很快,可是成对元素存放进去是没有顺序
的,那么我们要保证有序,还要速度快,就可以使用LinkedHashMap。

Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。注意,如果在映射中重新插入 键,则插入顺序不受影响。(如果在调用 m.put(k, v) 前 m.containsKey(k) 返回了 true,则调用时会将键 k 重新插入到映射 m 中。)

底层数据结构:数组+链表+双向链表


import java.util.LinkedHashMap;//HashMap的子类LinkedHashMap
public class LinkedHashMap01 {public static void main(String[] args) {LinkedHashMap<Integer,String> linked = new LinkedHashMap<>();linked.put(44,"开心");linked.put(5,"不开心");linked.put(777,"哈哈哈哈");System.out.println(linked);//{44=开心, 5=不开心, 777=哈哈哈哈}//这里输出就会按照程序插入顺序排列,与HashMap不一样}}

2.TreeMap<K,V>

基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

注意,如果要正确实现 Map 接口,则有序映射所保持的顺序(无论是否明确提供了比较器)都必须与 equals 一致。(关于与 equals 一致 的精确定义,请参阅 Comparable 或 Comparator)。这是因为 Map 接口是按照 equals 操作定义的,但有序映射使用它的 compareTo(或 compare)方法对所有键进行比较,因此从有序映射的观点来看,此方法认为相等的两个键就是相等的。即使排序与 equals 不一致,有序映射的行为仍然 定义良好的,只不过没有遵守 Map 接口的常规协定。

3.Hashtable<K,V>

此类实现一个哈希表,该哈希表将键映射到相应的值。任何非 null 对象都可以用作键或值。

为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和 equals 方法。

与HashMap对比: 

转至: https://blog.csdn.net/strivenoend/article/details/80396893

  1. 两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。

  2. HashMap可以使用null作为key,不过建议还是尽量避免这样使用。HashMap以null作为key时,总是存储在table数组的第一个节点上。而Hashtable则不允许null作为key。

  3. HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。

  4. HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。

  5. HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。

  6. HashMap和Hashtable的底层实现都是数组+链表结构实现。

  7. 两者计算hash的方法不同:
    Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模

  8. key和value是否允许null值

    Hashtable中,key和value都不允许出现null值。但是如果在Hashtable中有类似put(null,null)的操作,编译同样可以通过,因为key和value都是Object类型,但运行时会抛出NullPointerException异常,这是JDK的规范规定的。
    HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

  9. 两个遍历方式的内部实现上不同

    Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

  10. hash值不同

    哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

    hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。

    Hashtable计算hash值,直接用key的hashCode(),而HashMap重新计算了key的hash值,Hashtable在求hash值对应的位置索引时,用取模运算,而HashMap在求位置索引时,则用与运算,且这里一般先用hash&0x7FFFFFFF后,再对length取模,&0x7FFFFFFF的目的是为了将负的hash值转化为正值,因为hash值有可能为负数,而&0x7FFFFFFF后,只有符号外改变,而后面的位都不变。

  11. 内部实现使用的数组初始化和扩容方式不同

    HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。
     Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。 Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。

4.ConcurrentHashMap<K,V>

支持获取的完全并发和更新的所期望可调整并发的哈希表。此类遵守与 Hashtable 相同的功能规范,并且包括对应于 Hashtable 的每个方法的方法版本。不过,尽管所有操作都是线程安全的,但获取操作 必锁定,并且 支持以某种防止所有访问的方式锁定整个表。此类可以通过程序完全与 Hashtable 进行互操作,这取决于其线程安全,而与其同步细节无关。

底层数据结构:

JDK1.7: 数组 + 链表
                Segment数组 + hashEntry数组 + hashEntry链表
JDK1.8: 数组 + 链表|红黑树
               CAS + synchronized(同步锁)

与HashMap对比:

https://blog.csdn.net/xuefeng0707/article/details/40834595

二、JDK1.9新特性:of( )

通常,我们在代码中创建⼀个集合(例如,List 或 Set ),并直接⽤⼀些元素填充它。 实例化集合,⼏个 add⽅法 调⽤,使得代码重复。
Java 9,添加了⼏种集合⼯⼚⽅法,更⽅便创建少量元素的集合、map实例。新的List、Set、Map 的静态⼯⼚⽅法可以更⽅便地创建集合的不可变实例。
注意:
1:of() ⽅法只是Map,List,Set这三个接⼝的静态⽅法,其⽗类接⼝和⼦类实现并没有这类⽅法,⽐如 HashSet,ArrayList等等;
2:返回的集合是不可变的;

3. of()只能适用于List/Set/Map集合,不指定到实现类中

4.of()的返回值是一个不可改变的集合,否则都会抛出UnsupportedOperationException - 不支持的异常

5.Set/Map集合在调用of()的时候,不能有重复值,否则就会抛出IllegalArgumentException - 非法参数异常

import java.util.ArrayList;
import java.util.List;/*
* JDK1.9 新特性 of() 静态方法 接口名调用
* 插入值,就不用一个一个添加了
*
* */
public class Demo01 {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();//原始添加方法list.add(4);list.add(5);list.add(88);list.add(9);System.out.println(list);//[4, 5, 88, 9]List<Integer> list1 =List.of(2,8,5,6666,89,25);System.out.println(list1);//[2, 8, 5, 6666, 89, 25]//能获取集合里面的值System.out.println(list1.get(0));//2//不能增加元素//list1.add(555);//UnsupportedOperationException//不能更改里面的元素//list1.set(1,99);//UnsupportedOperationException//不能删除元素//list1.remove(2);//UnsupportedOperationExceptionSystem.out.println(list1);}
}

JAVA day20、21 双列集合Map<K,V>:HashMap,LinkedHashMap,TreeMap,Hashtable, ConcurrentHashMap;JDK1.9新特性相关推荐

  1. 【Java】如何理解Java中的双列集合Map?

    1 Map<K,V>接口 1.1 特点 双列集合一个元素包含俩值 Key不可以重复,Value可以重复 Key和Value一一对应 Key和Value可以时任意类型 1.2 常用方法 pu ...

  2. java 双列集合Map 万字详解

    目录 一.前言 二.概述 三.特点 四.常用方法 1. V put(K key, V value) : Δ代码演示 : 2. V get(Object key) : Δ代码演示 : 3. V remo ...

  3. java 中遍历双列集合_获取单列集合,双列集合,数组的Stream流对象以及简单操作...

    获取流对象 获取单列集合,双列集合,数组的流对象 单列集合获取流对象: 1.java.util.Collection接口中加入了default方法stream()获取流对象,因此其所有实现类均可通过此 ...

  4. 双列集合Map的实现类

    Map接口[和Collection接口并列] Map接口 成员方法[实现于Map接口,TreeMap也可实现,这里以HashMap为例] //HashMap实现类 :无序[HashSet底存原理] 哈 ...

  5. Java双列集合之Map以及斗地主案列

    Map集合 知识点-- 概述 讲解 图文演示 现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射.Java提供了专门的 ...

  6. java基础巩固-宇宙第一AiYWM:为了维持生计,多高(多线程与高并发)_Part9~整起(单双列集合们、ArrayList 的扩容机制、HashMap、ConcurrentHashMap )

    再进入正文之前,先看看集合相关操作的时间复杂度: 本故事源自于~ 开唠: PART0: 为什么突然蹦出集合这个玩意,就是因为咱们基础那里学的"数组"不够用~: 数组一般用来保存一组 ...

  7. Map双列集合的用法,遍历方法

    Map集合的常用方法. Map集合是一个双列集合,里面的每个元素都是一个键值对. Map<K,V> 有两个泛型, K 表示Map集合中键的类型. V 表示Map集合中值的数据类型. 常用方 ...

  8. Java中的Map集合及其子类HashMap,LinkedHashMap,TreeMap,ConcurrentHashMap

    一 .Map public interface Map<K,V> 将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值.此接口哦取代了Dictionary类,后者完全是 ...

  9. Java---Map双列集合

    目录 一.双列集合的介绍 二.Map的使用 1:Map中常见的API (1)put方法 (2)remove方法 2:Map的遍历 (1)通过键找值的方式遍历 (2)通过键值对对象遍历 (3)Lambd ...

最新文章

  1. Java 15 转正了,国内几大互联网公司均有贡献,其中腾讯最为突出!
  2. ML 01、机器学习概论
  3. 转:Jeff Dean的Stanford演讲
  4. boost::endian模块实现benchmark的测试程序
  5. defer和async属性详解
  6. java模拟火车站买票的过程_Java常用代理
  7. 项目开发日志:Build AssetBundle——SpriteAtlas(已解惑)
  8. try catch php 捕获,php try catch : 捕捉异常,抛出异常
  9. python协成_Python协程技术的演进
  10. [实验流体力学][Matlab] pi 定理的应用
  11. 内核线程和用户线程(SMP)
  12. 什么叫做形态学图像处理_形态学腐蚀和膨胀原理和python实现
  13. 操盘手 李彪 照片[转]
  14. 【“科大讯飞杯”第十七届同济大学】A 张老师和菜哭武的游戏
  15. 有一个Map集合里面存储的是学生的姓名和年龄,内容如下{赵四=21,王二=17,张三=18,小丫=25,李四=26,王五=38}(15分) * a.将里面的元素用两种遍历方式打印到控制台上 *
  16. java 截取图片后缀
  17. 面经手册 · 第1篇《认知自己的技术栈盲区》
  18. 从专升本到互联网大厂-我的2021
  19. FFmpeg简单使用:视频编码 ---- YUV转H264
  20. Linux应用开发: SQLite数据库交叉编译部署与运用

热门文章

  1. 地热热泵系统行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  2. echarts-X轴不从0刻度开始 代码实现
  3. Web工程师必备的可视化工具
  4. vue2.0的Element UI的表格table列时间戳格式化
  5. Go 应用优化“指北”
  6. 这就是程序员被大厂偏爱的实力!
  7. 堪称神器的命令行工具系列——curl
  8. 打破“打工人”魔咒,RPA 来狙击!
  9. 不要再被Python洗脑了,来看看这个吧......
  10. 疫情下的国内云市场,正是大展拳脚的好时机!