Java集合容器介绍

news2024/12/23 18:27:02
  • Java 容器分为 Collection 和 Map 两大类,其下又有很多子类,如下所示:
    collections.png
  • Collection接口:单列数据,定义了存取一组对象的方法的集合

1、List:元素有序(指的是存储时,与存放顺序保持一致)、可重复的集合
2、Set:元素无序、不可重复的集合

Maps.png

  • ArrayList和LinkedList、Vector比较

1、二者都线程不安全,相对线程安全的Vector,执行效率高。此外,ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。对于新增和删除操作add(特指插入)和remove,LinkedList比较占优势,因为ArrayList要移动数据。

1、Vector和ArrayList几乎是完全相同的,唯一的区别在于Vector是同步类(synchronized),属于强同步类,访问要慢,同时开销也比ArrayList要大,Vector每次扩容请求其大小的2倍空间,而ArrayList是1.5倍

++ 补充++

  • Set接口

1、Set接口是Collection的子接口,set接口没有提供额外的方法

2、Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败。

3、Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals() 方法

  • Set实现类之一:HashSet

1、HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。

2、HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除性能。

3、HashSet 具有以下特点:不能保证元素的排列顺序、HashSet 不是线程安全的、集合元素可以是 null

4、HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。

5、对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”

  • 向HashSet中添加元素的过程

1、当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值,通过某种散列函数决定该对象在 HashSet 底层数组中的存储位置。(这个散列函数会与底层数组的长度相计算得到在数组中的下标,并且这种散列函数计算还尽可能保证能均匀存储元素,越是散列分布,该散列函数设计的越好)

2、如果两个元素的hashCode()值相等,会再继续调用equals方法,如果equals方法结果为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了,那么会通过链表的方式继续链接。

3、如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

  • 重写 equals() 方法的基本原则

1、当一个类有自己特有的“逻辑相等”概念,当改写equals()的时候,总是要改写hashCode(),根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode()方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。

1、结论:复写equals方法的时候一般都需要同时复写hashCode方法。通常参与计算hashCode的对象的属性也应该参与到equals()中进行计算。

  • LinkedHashSet

1、LinkedHashSet 是 HashSet 的子类

2、LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

3、LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

4、LinkedHashSet 不允许集合元素重复

  • TreeSet

1、TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。

2、TreeSet底层使用红黑树结构存储数据

3、TreeSet 两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序

自然排序 TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列。

1、如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过compareTo(Object obj) 方法的返回值来比较大小。

2、Comparable 的典型实现

1、BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较

2、Character:按字符的 unicode值来进行比较

3、Boolean:true 对应的包装类实例大于 false 对应的包装类实例

4、String:按字符串中字符的 unicode 值进行比较

5、Date、Time:后边的时间、日期比前面的时间、日期大

3、向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。

4、因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象

5、对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 方法比较返回值

6、当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0。否则,让人难以理解。

  • Map接口

1、Map与Collection并列存在。用于保存具有映射关系的数据:key-value

2、Map 中的 key 和 value 都可以是任何引用类型的数据
Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写 hashCode()和equals() 方法

3、常用String类作为Map的“键”

4、key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value

5、Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和Properties。其中,HashMap是 Map 接口使用频率最高的实现类

  • HashMap的存储结构

1、JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)

jdk7.png

2、JDK 8版本发布以后:HashMap是数组+链表+红黑树实现。

jdk81.png

  • HashMap源码中的重要常量

1、DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16

2、MAXIMUM_CAPACITY : HashMap的最大支持容量,2^30

3、DEFAULT_LOAD_FACTOR:HashMap的默认加载因子

4、TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树

5、UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表

6、MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。(当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。)
7、table:存储元素的数组,总是2的n次幂

8、entrySet:存储具体元素的集

9、size:HashMap中存储的键值对的数量

10、modCount:HashMap扩容和结构改变的次数。

11、threshold:扩容的临界值,=容量*填充因子

12、loadFactor:填充因子

  • HashMap的存储结构:JDK 1.8之前

1、HashMap的内部存储结构其实是数组和链表的结合。当实例化一个HashMap时,系统会创建一个长度为Capacity的Entry数组,这个长度在哈希表中被称为容量(Capacity),在这个数组中可以存放元素的位置我们称之为“桶”(bucket),每个bucket都有自己的索引,系统可以根据索引快速的查找bucket中的元素。
2、每个bucket中存储一个元素,即一个Entry对象,但每一个Entry对象可以带一个引用变量,用于指向下一个元素,因此,在一个桶中,就有可能生成一个Entry链。而且新添加的元素作为链表的head。

  • HashMap添加元素的过程

0、向HashMap中添加entry1(key,value),

1、首先计算entry1中key的哈希值(根据key所在类的hashCode()计算得到),此哈希值经过处理以后,得到在底层Entry[]数组中要存储的位置i。如果位置i上没有元素,则entry1直接添加成功。

2、如果位置i上已经存在entry2(或还有链表存在的entry3,entry4),则需要通过循环的方法,依次比较entry1中key和其他的entry。如果彼此hash值不同,则直接添加成功。

3、如果hash值相同,继续比较二者是否equals。如果返回值为true,则使用entry1的value去替换equals为true的entry的value;如果遍历一遍以后,发现所有的equals返回都为false,则entry1仍可添加成功。entry1指向原有的entry元素。

hashmapput.png

  • HashMap的扩容

1、当HashMap中的元素越来越多的时候,hash冲突的几率也就越来越高,因为数组的长度是固定的。所以为了提高查询的效率,就要对HashMap的数组进行扩容,而在HashMap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize。

2、当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数size)loadFactor 时 , 就 会 进 行 数 组 扩 容 , loadFactor 的默认 值 (DEFAULT_LOAD_FACTOR)为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小(DEFAULT_INITIAL_CAPACITY)为16,那么当HashMap中元素个数超过160.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。

  • 负载因子值的大小,对HashMap有什么影响?

1、负载因子的大小决定了HashMap的数据密度。

2、负载因子越大密度越大,发生碰撞的几率越高,数组中的链表越容易长,造成查询或插入时的比较次数增多,性能会下降。

3、负载因子越小,就越容易触发扩容,数据密度也越小,意味着发生碰撞的几率越小,数组中的链表也就越短,查询和插入时比较的次数也越小,性能会更高。但是会浪费一定的内容空间。而且经常扩容也会影响性能,建议初始化预设大一点的空间。

4、按照其他语言的参考及研究经验,会考虑将负载因子设置为0.7~0.75,此时平均检索长度接近于常数。

  • HashMap的存储结构:JDK 1.8

1、HashMap的内部存储结构其实是数组+链表+树的结合。当实例化一个HashMap时,会初始化initialCapacity和loadFactor,在put第一对映射关系时,系统会创建一个长度为initialCapacity的Node数组,这个长度在哈希表中被称为容量(Capacity),在这个数组中可以存放元素的位置我们称之为“桶”(bucket),每个bucket都有自己的索引,系统可以根据索引快速的查找bucket中的元素。

2、每个bucket中存储一个元素,即一个Node对象,但每一个Node对象可以带一个引用变量next,用于指向下一个元素,因此,在一个桶中,就有可能生成一个Node链。也可能是一个一个TreeNode对象,每一个TreeNode对象可以有两个叶子结点left和right,因此,在一个桶中,就有可能生成一个TreeNode树。而新添加的元素作为链表的last,或树的叶子结点。

  • HashMap什么时候进行扩容和树形化?

1、当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数size)loadFactor 时 , 就会进行数组扩容 , loadFactor 的默认 值 (DEFAULT_LOAD_FACTOR)为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小(DEFAULT_INITIAL_CAPACITY)为16,那么当HashMap中元素个数超过160.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。

2、当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树,结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。

  • LinkedHashMap

1、LinkedHashMap 是 HashMap 的子类

2、在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序

3、与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致

//HashMap中的内部类:Node
static class Node<K,V> implements Map.Entry<K,V> {
	final int hash;
	final K key;
	V value;
	Node<K,V> next; 
}

//LinkedHashMap中的内部类:Entry
static class Entry<K,V> extends HashMap.Node<K,V> {
	Entry<K,V> before, after;
	Entry(int hash, K key, V value, Node<K,V> next) {
		super(hash, key, value, next);
	} 
}

  • TreeMap

1、TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。

2、TreeSet底层使用红黑树结构存储数据

3、TreeMap 的 Key 的排序:

1、自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException

2、定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现Comparable 接口

4、TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0。

  • Hashtable

1、Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的。

2、Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用。

3、与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value

4、与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序

5、Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。

  • Properties

1、Properties 类是 Hashtable 的子类,该对象用于处理属性文件

2、由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型

3、存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法

Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/148660.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Docker】(四)使用volume持久化Docker容器中的Redis数据

1.前言 本系列文章记录了从0开始学习Docker的过程&#xff0c;Docker系列历史文章&#xff1a; &#xff08;一&#xff09;基本概念与安装使用 &#xff08;二&#xff09;如何使用Docker发布一个SpringBoot服务 &#xff08;三&#xff09;使用registry远程镜像仓库管理镜像…

[ 数据结构 ] 赫夫曼编码--------数据、文件压缩解压

0 引出 如上图:给定字符串按定长编码处理,最终对应二进制长度为359 思考:如何压缩,将359有效降低? ----回顾:赫夫曼树 1 数据压缩 拿到数据(字符串)的第一反应,虽然知道应该也像上面一样转为字节数组,但就不知道该怎么办了?统计数组中各字节使用的次数,将次数作为权值,字节…

2023.1.8 学习周报

文章目录摘要文献阅读1.题目2.摘要3.介绍4.论文主要贡献5.相关工作5.1 序列感知的推荐系统5.2 神经注意模型6.模型&#xff1a;ATTREC6.1 序列推荐6.2 基于Self-Attention的用户短期兴趣建模6.3 用户长期兴趣建模6.4 模型学习7.实验7.1 数据集7.2 评估指标7.3 模型比较7.4 实验…

SSO单点登录实例详解(前端传Code授权登录)

什么是 SSO&#xff08;单点登录&#xff09; SSO 英文全称 Single Sign On&#xff0c;单点登录。SSO 是在多个应用系统中&#xff0c;用户只需要登录一次就可以访问所有相互信任的应用系统。 单点登录流程 单点登录大致流程如下所示&#xff1a; 单点登录详细流程&#x…

【自学C++】C++变量初始化

C变量初始化 C变量初始化教程 变量 的初始化就是在定义变量的同时&#xff0c;给变量设置一个初始值&#xff0c;在 C 中&#xff0c;如果定义变量没有初始化&#xff0c;那么变量有可能会被赋值也有可能不会赋值。 如果是定义的 全局变量 或者 静态变量&#xff0c;未初始化…

2022年语音合成(TTS)和语音识别(ASR)年度总结

论文统计每月更新一次&#xff0c;主要跟踪语音合成和语音识别的发展状况(很多文章都是在会议后才发出&#xff0c;但不影响统计。统计过程难免存在疏漏&#xff0c;因此统计结果仅供参考。所有文章语音合成领域统计列表请访问http://yqli.tech/page/tts_paper.html&#xff0c…

绝大多数人远远低估了软件开发的难度

给你付钱了&#xff0c;你应该把软件做好&#xff01; 这个话相当于&#xff1a; 给你付钱了&#xff0c;你应该把月亮摘下来&#xff01; 趣讲大白话&#xff1a;臣妾做不到 ********** 软件是特殊商品服务 可以说很难有标准 开发的难度取决于需求多少&#xff0c;技术难度&a…

Java Map集合的介绍和使用

什么是Map类型的集合 介绍 1.用于保存具有映射关系的数据&#xff08;key——value&#xff09;。 2.Map中的key和value可以是任意的类型的数据。 3.Map中的key值不允许重复。 4.Map中的value值可以重复。 5.一般常用string作为value的key。 6.key和value之间存在一一对…

如何进行地图SDK开发(二)——示例文档

概述 前面的文章文章我们写到了SDK的开发以及ak认证的实现&#xff0c;在本文我们继续讲讲地图SDK开发中的示例文档的实现。 技术点 vue3viteelement-plusmonaco-editor 实现后效果 实现 1. 工程初始化 1.1 搭建工程 搭建工程的过程请参照博文(使用vite搭建vue3项目&…

javaEE初阶 — 线程池

文章目录线程池1 什么是线程池2 标准库中的线程池2.1 什么是工厂模式2.2 如何使用标准库中的线程池完成任务2.3 ThreadPoolExecutor 构造方法的解释3 实现一个线程池线程池 1 什么是线程池 随着并发程度的提高&#xff0c;随着对性能要求标准的提高会发现&#xff0c;好像线程…

[cpp进阶]C++异常

文章目录C语言传统处理错误的方式C异常概念C异常使用异常的抛出和捕获异常的重新抛出异常安全异常规范自定义异常体系C标准库的异常体系异常的优缺点C语言传统处理错误的方式 传统的错误处理机制&#xff1a; 终止程序。assert断言直接终止程序。缺点&#xff1a;过于粗暴&am…

Fiddler抓取手机APP报文

Http协议代理工具有很多&#xff0c;比如Burp Suite、Charles、Jmeter、Fiddler等&#xff0c;它们都可以用来抓取APP报文&#xff0c;其中charles和Burp Suite是收费的&#xff0c;Jmeter主要用来做接口测试&#xff0c;而Fiddler提供了免费版&#xff0c;本文记录一下在Windo…

位运算做加法,桶排序找消失元素,名次与真假表示,杨氏矩阵,字符串左旋(外加两道智力题)

Tips 1. 2. 3. 大小端字节序存储这种顺序只有在放进去暂时存储的时候是这样的&#xff0c;但是一旦我里面的数据需要参与什么运算之类的&#xff0c;会“拿出来”先恢复到原先的位置再参与运算&#xff0c;因此&#xff0c;大小端字节序存储的什么顺序不影响移位运算等等…

【案例教程】CLUE模型构建方法、模型验证及土地利用变化情景预测实践技术

【前沿】&#xff1a;土地利用/土地覆盖数据是生态、环境和气象等领域众多模型的重要输入参数之一。基于遥感影像解译&#xff0c;可获取历史或当前任何一个区域的土地利用/土地覆盖数据&#xff0c;用于评估区域的生态环境变化、评价重大生态工程建设成效等。借助CLUE模型&…

声音产生感知简记

声音产生 人的发音器官包括:肺、气管、声带、喉、咽、鼻腔、口腔、唇。肺部产生的气流冲击声带,产生震动。 声带每开启和闭合一次的时间是基音周期(Pitch period,T),其到数为基音频率(F.=1/T,基频),范围在70-450Hz。基频越高,声音越尖细,如小孩的声音比大人尖,就是…

编译错误2

本文迁移自本人网易博客&#xff0c;写于2015年11月25日&#xff0c;编译错误2 - lysygyy的日志 - 网易博客 (163.com)1、error C2059:语法错误&#xff1a;“<L_TYPE_RAW>”error C2238:意外的标记位于“;”之前.错误代码定位于&#xff1a;BOOL TreeView_GetCheckState…

excel函数公式:常用高频公式应用总结 上篇

公式1&#xff1a;条件计数条件计数在Excel的应用中十分常见&#xff0c;例如统计人员名单中的女性人数&#xff0c;就是条件计数的典型代表。条件计数需要用到COUNTIF函数&#xff0c;函数结构为COUNTIF(统计区域,条件)&#xff0c;在本例第一个公式COUNTIF(B:B,G2)中&#xf…

《栈~~队列~~优先级队列》

目录 前言&#xff1a; 1.stack 1.stack的介绍 2.stack的使用&#xff1a; 3.stack的模拟实现 4.有关stack的oj笔试题 2.queue 1.队列的介绍 2.队列的使用 3.队列的模拟实现 4.有关队列的oj笔试题 3.priority_queue 1.优先级队列的介绍 2.优先级队列的使用 3.优先级队列的模拟实…

挥别2022,坦迎2023。

第一章&#xff1a;CSDN&#xff0c;我来啦&#xff01;第一节&#xff1a;初遇&#xff01;2022-08-13&#xff0c;我和CSDN相遇啦&#xff01;CSDN&#xff0c;你好呀&#xff01;2022年8月13日&#xff0c;是我与你相遇的日子。这是一个值得纪念的时刻。从此之后&#xff0c…

English Learning - L1-10 时态(下) 2023.1.5 周四

English Learning - L1-10 时态&#xff08;下&#xff09; 2023.1.5 周四8 时态8.3 完成时态核心思想&#xff1a;回首往事&#xff08;一&#xff09;现在完成时核心思想用法延续动作延续时间 “动作一直持续了。。。”延续动&#xff08;无延续时间&#xff09; “做过。。…