Map接口、HashMap类、Treemap类、Hashtable类、Theard类 2022.6.23

本文详细介绍了Java集合框架中的Map接口,包括其特点、方法和常见实现类如HashMap、LinkedHashMap、TreeMap和Hashtable。HashMap是基于哈希表的数据结构,JDK8引入了红黑树优化;LinkedHashMap保持插入顺序;TreeMap则根据键的自然顺序或自定义比较器进行排序。此外,还讨论了线程安全和并发问题,以及线程和进程的概念。
Map接口
*      接口的特点
*          1.双列集合的顶级接口
*          2.Map集合以"对"为单位进行存储,其中一个key,一个value
*          3.key和value之间的关系是"映射关系"
*          4.key和value的泛型类型可以相同,也可以不同
*          5.在映射关系中,key不可以重复,value可以重复
*      接口的位置
*          java.util
*      接口的方法
*          V put(K key,V value)
*              将指定的值与此映射中的指定键关联(可选操作)。
*          void clear()
*              从此映射中移除所有映射关系(可选操作)。
*          boolean containsKey(Object key)
*              如果此映射包含指定键的映射关系,则返回 true。
*          boolean containsValue(Object value)
*              如果此映射将一个或多个键映射到指定值,则返回 true。
*          V get(Object key)
*              返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
*          boolean isEmpty()
*              如果此映射未包含键-值映射关系,则返回 true。
*          V remove(Object key)
*              如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
*          int size()
*              返回此映射中的键-值映射关系数
*          Set<K> keySet()
*              返回此映射中包含的键的 Set 视图。
*          Collection<V> values()
*              返回此映射中包含的值的 Collection 视图。
*          Set<Map.Entry<K,V>> entrySet()
*              返回此映射中包含的映射关系的 Set 视图。
*          default void forEach(BiConsumer<? super K, ? super V> action)
*              针对map进行遍历

Map.Entry<K,V>接口
*      接口的特点
*          以key和value封装对象的集合
*      接口的位置
*          Map接口中的Entry<K,V>
*      接口的方法
*          K getKey()
*              返回与此项对应的键。
*          V getValue()
*              返回与此项对应的值。

HashMap类
*      类的特点
*          1.HashMap集合的底层数据结构是"哈希表"
*              JDK7.0(包含)以前:存储链表对象的数组
*              JDK8.0(包含)以后:存储链表对象或者红黑树对象的数组
*          2.HashMap集合可以存储null值和null键,使用键或值的时候需要进行非空校验,防止空指针异常
*          3.HashMap集合是无序的集合
*          4.HashMap集合无法保证元素在集合中的位置永远不会改变
*          5.HashMap集合是线程不安全的,只适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全
*      类的位置
*          java.util
*      类的构造器
*          public HashMap()
*              构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
*      类的方法
*          详见Map接口的常用方法

HashMap集合元素存储过程的源码分析(基于JDK8.0):
*      1.相关名词解释
*          桶:底层数组的实时长度
*          桶元素:底层数组中存储的元素(null,链表对象,红黑树)
*          初始容量:底层数组的初始长度
*          加载因子:底层数组的进行扩容前阈值的参数
*          阈值:底层数组扩容前的标准
*              阈值 = (int)(底层数组长度 * 加载因子)
*      2.涉及成员变量,成员常量和方法的局部变量的备忘录
*          成员变量或成员常量:
*              DEFAULT_INITIAL_CAPACITY(int):底层数组默认的初始长度
*              MAXIMUM_CAPACITY(int):底层数组最大长度
*              DEFAULT_LOAD_FACTOR(float):默认的加载因子
*              TREEIFY_THRESHOLD(int):树化标准之一,链表对象的判断条件
*              UNTREEIFY_THRESHOLD(int):链表化标准,红黑树结构中结点对象的数量
*              MIN_TREEIFY_CAPACITY(int):树化标准之一,底层数组进行树化最小长度
*              table(Node<K,V>[]):底层数组
*              entrySet(Set<Map.Entry<K,V>>):底层键值对对象的集合
*              size(int):集合中元素的数量
*              modCount(int):集合中元素的计数器变量
*              threshold(int):扩容前的阈值变量
*              loadFactor(float):加载因子变量
*          putVal()的局部变量:
*              hash(int):通过key的hashCode重新计算的hash值
*              key(K):待添加元素的键
*              value(V):待添加元素的值
*              tab(Node<K,V>[]):待存储操作的底层数组
*              p(Node<K,V>):待存储元素在底层数组中待存储的索引位置上的桶元素
*              n(int):待存储操作底层数组的长度
*              i(int):待存储元素在底层数组中待存储的索引位置
*              e(Node<K,V>):当前红黑树对象或链表对象的下一位对象
*              k(K):待存储元素在底层数组中待存储的索引位置上的桶元素的key
*          resize()的局部变量:
*              oldTab(Node<K,V>[]):待重置前操作的底层数组
*              oldCap(int):待重置前操作底层数组的长度
*              oldThr(int):待重置前操作底层数组的阈值
*              newCap(int):待重置后操作底层数组的长度
*              newThr(int):待重置后操作底层数组的阈值
*          hash(Object key)的局部变量
*              h(int):key的hashCode值
*          treeifyBin()的局部变量:
*              n(int):底层待操作数组的长度
*              index(int):
*              e(Node<K,V>):
*      3.底层数组的初始容量和初始加载因子
*          初始容量和初始加载因子是多少取决于创建对象时的构造器
*          (1)HashMap()
*              初始容量:创建对象时没有进行初始化操作,会在第一次添加元素时进行初始化操作,初始容量为16
*              初始加载因子:0.75
*          (2)HashMap(int initialCapacity)
*              初始容量:自定义
*              初始加载因子:0.75
*          (3)HashMap(int initialCapacity, float loadFactor)
*              初始容量:自定义
*              初始加载因子:自定义
*          (4)HashMap(Map<? extends K,? extends V> m)
*              初始容量:参数集合的长度
*              加载因子:参数集合长度的加载因子
*      4.第一次添加元素时的扩容规则
*          扩容规则:16
*      5.如何确认元素在底层数组中的索引位置
*          (1)将key的hashCode值重新计算hash值
*              代码:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
*              解释:hash值的补码32位中,高16位的补码和hashCode值的高16位补码相同,低16位是hashCode值的高16位补码和hashCode值
*              的低16位补码进行按位异或
*              目的:重新计算hashCode是为了将元素可以更加均匀分布在各个桶之间
*          (2)根据hash值和底层数组长度计算存储的索引位置
*              代码:(n - 1) & hash
*              解释:将hash值和底层数组长度-1进行按位与,得到结果是该元素在底层数组中存储的索引位置
*      6.后续添加元素时的扩容规则
*          扩容规则:
*              原来底层数组长度 << 1
*      7.底层数组中链表对象何时进行红黑树对象的转换(树化)
*          (1)链表对象长度达到8时
*          (2)底层数组长度达到64
*      8.底层数组中红黑树对象何时进行链表对象的转换(链表化)
*          (1)红黑树结构中结点对象的数量降至6个
*      9.JDK7.0和JDK8.0的区别
*          (1)底层数组的桶元素内容不同
*              JDK7.0(包含)以前:null,链表对象
*              JDK8.0(包含)以后:null,链表对象,红黑树对象
*          (2)底层数组的数据类型不同
*              JDK7.0(包含)以前:Entry<K,V>[]
*              JDK8.0(包含)以后:Node<K,V>[]
*          (3)无参构造器底层数组的初始容量不同:
*              JDK7.0(包含)以前:16
*              JDK8.0(包含)以后:创建对象时没有进行初始化操作,会在第一次添加元素时进行初始化操作,初始容量为16\
*          (4)hash算法不同:
*              JDK7.0(包含)以前:
*                  h ^= k.hashCode();
*                  h ^= (h >>> 20) ^ (h >>> 12);
*                  h ^ (h >>> 7) ^ (h >>> 4);
*              JDK8.0(包含)以后:
*                  (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
*          (5)底层数组的扩容规则:
*              JDK7.0(包含)以前:
*                  2 * 原来底层数组长度
*              JDK8.0(包含)以后:
*                  原来底层数组长度 << 1
*
*
* 默认的加载因子为什么是0.75?
*      默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询(时间)成本;加载
*      因子过低虽然减少了查询(时间)开销,但同时也增加了空间成本;


LinkedHashMap类
*      类的特点
*          1.LinkedHashMap集合的底层数据结构是"哈希表+链表"
*              链表的作用:维护元素的有序性
*          2.LinkedHashMap集合是有序的集合
*          3.LinkedHashMap集合可以存储null值和null键,使用键或值的时候需要进行非空校验,防止空指针异常
*          4.LinkedHashMap集合是线程不安全的,只适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全
*      类的位置
*          java.util
*      类的构造器
*          public LinkedHashMap()
*              构造一个带默认初始容量 (16) 和加载因子 (0.75) 的空插入顺序 LinkedHashMap 实例。
*      类的方法
*          详见Map接口的常用方法

TreeMap类
*      类的特点
*          1.TreeMap集合底层的数据结构是"红黑树结构"
*          2.TreeMap集合可以根据映射关系中键的自然顺序进行排序,或者根据创建映射时提供的 Comparator进行排序,具体取决于使用的构造方法。
*          3.TreeMap集合无序的集合
*          4.TreeMap集合不可以存储null键,存储时需要针对每个键进行非空校验,防止空指针异常,并且TreeMap集合可以存储null值,但获取
*          时需要针对每个值进行非空校验,防止空指针异常
*          5.TreeMap集合是线程不安全的,适用于单线程程序,如果在多线程中进行使用需要手动添加线程安全
*      类的位置
*          java.util
*      类的构造器
*          public TreeMap()
*              使用键的自然顺序构造一个新的、空的树映射。
*          public TreeMap(Comparator<? super K> comparator)
*              构造一个新的、空的树映射,该映射根据给定比较器进行排序
*      类的方法
*          详见Map集合的常用方法

Hashtable类
*      类的特点
*          1.Hashtable集合底层的数据结构是"哈希表"
*              哈希表:存储链表对象的数组
*          2.Hashtable集合不可以存储null键和null值,需要在存储元素时进行非空校验,防止空指针异常
*          3.Hashtable集合是无序集合
*          4.Hashtable集合无法保证元素的顺序永远不会改变
*          5.Hashtable集合是线程安全的,适用于多线程程序,如果在单线程中进行使用,执行效率过低
*      类的位置
*          java.util
*      类的构造器
*          public Hashtable()
*              用默认的初始容量 (11) 和加载因子 (0.75) 构造一个新的空哈希表。
*      类的方法
*          常见Map集合的常见方法

HashMap和Hashtable之间的区别:
*      1.null键和null值是否可以存储不同
*          HashMap:可以
*          Hashtable:不可以
*      2.线程安全性不同
*          HashMap:线程不安全
*          Hashtable:线程安全
*      3.使用无参构造器创建对象时底层数组的初始容量不同
*          HashMap:
*              JDK7.0(包含)以前:16
*              JDK8.0(包含)以后:先不进行初始化,在第一次添加元素时初始化16
*          Hashtable:11
*      4.底层数组存储桶元素不同
*          HashMap:
*              JDK7.0(包含)以前:null,链表对象
*              JDK8.0(包含)以后:null,链表对象,红黑树对象
*          Hashtable:
*              null,链表对象
*      5.底层数组的扩容规则不同:
*          HashMap:
*              JDK7.0(包含)以前:
*                  2 * 原来底层数组长度
*              JDK8.0(包含)以后:
*                  原来底层数组长度 << 1
*          Hashtable:
*              JDK6.0(包含)以前:
*                  原来底层数组长度 * 2 + 1;
*              JDK7.0(包含)以后:
*                  (原来底层数组长度 << 1) + 1

Properties类
*      类的特点
*          Properties 类表示了一个持久(存储在硬盘中)的属性集(配置文件)。
*      类的位置
*          java.util
*      类的构造器
*          public Properties()
*              创建一个无默认值的空属性列表。
*      类的方法
*          public String getProperty(String key)
*              用指定的键在此属性列表中搜索属性。
*          public void load(InputStream inStream)
*              从输入流中读取属性列表(键和元素对)。
*          public void load(Reader reader)
*              按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
*          public Set<String> stringPropertyNames()
*              返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键


并发和并行:
*      并发:在同一时间段内发生的多件事情
*      并行:在同一时间发生的多件事情
*
* 进程和线程:
*      CPU核心执行规则:每个核心在所有进程中进行高速无规则的切换动作
*      进程:操作系统中的应用程序,每个应用程序至少包含一条进程,程序进程由CPU核心进行控制
*      线程:每个进程中的线程,每条进程至少包含一条线程,程序线程由CPU核心中的线程进行控制

Thread类
*      类的特点
*          线程 是程序中的执行线程
*      类的位置
*          java.lang
*      类的构造器
*          public Thread()
*              分配新的 Thread 对象。
*          public Thread(String name)
*              分配新的 Thread 对象。
*          public Thread(Runnable target)
*              分配新的 Thread 对象
*          public Thread(Runnable target,String name)
*              分配新的 Thread 对象
*      类的方法
*          public static Thread currentThread()
*              返回对当前正在执行的线程对象的引用。
*          public final String getName()
*              返回该线程的名称。
*          public static void sleep(long millis)
*              在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
*          public void run()
*              如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;
*              否则,该方法不执行任何操作并返回。
*          public void start()
*              使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值