集合(List、Set、Map)ArrayList、LinkedList、Vector、HashSet、LinkedHashSet、HashMap

news/2025/1/6 4:44:39/

集合:

集合是动态保存多个任意对象,使用增加、删除元素时比较方便(自动扩缩容,不需要自己编写逻辑);

集合有单列集合Collection双列集合Map

        其中Collection有两个子接口:Set、List;

                List:有序、可以重复、支持索引、允许有多个null;

                        有三种遍历方式(迭代器、增强for、普通for (因为有索引));

                        List有实现类:ArrayList、LinkedList、Vector;

                Set:无序、不可以重复、最多有一个null、无索引;

                        有两种遍历方式:迭代器、增强for;

                        取出的顺序和添加的顺序不一样,但只要取了 一次,每次都一样;

                        Set有实现类:HashSet、LinkedHashSet、TreeSet;

        Map有三个实现类:HashMap、Hashtable、TreeMap;

                保存的是具有映射关系的键值对key-value;

                key和value可以是任何引用类型的数据,会封装到HashMap&Node中;

                key不允许重复,value可以重复;

                key可以为null,但只能有一个,value可以为null,可以有多个;

                一对key-value保存到Node中,而Node又实现Entry接口,所以Map有三种遍历方式:

keySet:获取所有键的集合,用get(key)通过键获得对应的值;

values:获取所有值的集合,但无法获取对应的键;

entrySet:获取所有键值对的Set集合,每个元素都是一个Map.Entry对象,代表一个键值对;

迭代器Iterator:所有实现Collection接口的集合类都有一个iterator()方法,遍历集合,并返回一个实现了Iterator接口的对象,但他本身并不存放对象;

Iterator.hashNext():判断是否还有下一个元素;

Iterator.next():光标下移,并将下移后集合的元素返回;

        注:在iterator.next()前必须先使用iterator.hashNext来判断一下受否还有下一个元素,否则将会抛出异常;

增强for就是简易版的迭代器;

ArrayList:

        允许有null,可以多个null;

        是由数组来实现数据存储的;

        基本等同于Vector,除了ArrayList是线程不安全(但执行效率高),在多线程情况下不建议使用;

        扩容机制:ArrayList中维护了一个Object类型的数组elementDate:

                translent Object[] elementDate;其中translent表示短暂的,该属性不会被序列化;

                当创建ArrayList对象时,如果使用的是无参构造器,则elementDate初始容量为0,第一添加时,会扩容到10,再次扩容时elementDate容量会扩容到10*1.5=15,以此类推;

如果使用的是指定大小的构造器,则elementDate初始容量为指定的大小,如果需要扩容时,则直接扩容为1.5倍,以此类推;

LinkedList:

        底层维护了一个双向链表;

        LinkedList中维护了两个属性first和last,其中first指向首节点,las指向尾节点;

        每个节点(Node对象)里又维护了三个属性pre、next、item,其中通过pre指向前一个节点、next指向后一个节点、item指向实际数据元素;

        LinkedList的添加、删除不是通过数组来完成的,而是通过调整节点引用来完成元素的添加和删除的,所以效率更高;

        线程不安全,没有实现同步;

LinkedList和ArrayList比较:

ArrayList底层维护的是数组,因为有索引,所以改查效率更高一点;

LinkedList底层维护的是链表,因为增删可以直接通过修改链表的指向即可,所以增删的效率更高一点;

Vector:

        底层也是一个对象数组:protected Object[] elementDate;

         Vector是线程同步的(即线程安全),Vector中的操作方法synchronized;

         扩容机制:创建Vector对象时,如果使用的是无参构造器,则elementDate初始容量为10,如果需要扩容时,会扩容到2倍,以此类推;

                如果使用的是有参构造器,则elementDate的初始容量为指定的大小,如果需要扩容时,则直接扩容为2倍,以此类推;

HashSet:

        底层是HashMap,HashMap底层是数组+链表+红黑树;

        添加一个元素时,先通过计算得到哈希值,然后转变成数组的索引值,根据索引值来看存储数据表table中的对应位置是否已经有存放的元素:

                如果没有则直接添加到数组中(链表的头节点);

                如果有则调用equals()来比较:如果相同就放弃添加;

                                                                如果不相同则添加到链表的最后;

        因为HashSet的底层是HashMap,所以当一条链表的元素个数达到8,且数组中的个数 >= 64,就会进行树化(红黑树);

扩展:

根据 Java 官方文档和 HashMap 的源码实现,链表转换为红黑树的条件是:

  • 链表长度 >= 8:一个桶(bucket)中的链表长度达到了 8
  • 数组长度 >= 64HashMap 的数组长度(即桶的数量)已经达到了 64 或更大。

这两个条件必须同时满足,才会触发链表到红黑树的转换。如果其中一个条件不满足,即使链表长度达到了 8,也不会进行树化。它仍然还会保持链表的形式。

LinkedHashSet:

        底层是一个LinkedHashMap,底 层维护了一个数组+双向链表;

        每一个节点有属性before和after,这样就形成了双向链表;

        在添加一个元素时,先求哈希值来确定元素位置,如果没有相同的则直接添加到双向链表中,如果相同则不添加(和HashSet一样):

        如果相等:不执行任何操作,因为集合不允许重复元素;

        如果不相等:将新节点插入到双向链表的尾部,并更新相关指针,如:

                tail.after = newElement;

                newElement.before = tail;

                tail = newElement;

                其中tail尾节点,newElement新添加的元素;

HashMap:

        当添加相同的key时,则会覆盖原来的key-value,等同于 修改,但key不会被替换,value会被替换;

        没有实现同步,线程不安全;

        底层维维护了Node类型的数组table : Node<K,V>[] table 数组,默认为null;

        扩容机制:当创建对象时,加载因子初始为0.75;

                当添加元素时,通过key的哈希值来得出在table的索引,判断该索引处是否有元素:

                        如果没有直接添加;

                       如果有再判断key是否相等:

                                如果相等则覆盖(替换value);

                                如果key不相等则需判断是树结构还是链表结构并作出相应处理:

                                        如果是链表:将新节点插入链表尾部;

                                        如果是红黑树:按照红黑树规则插入新节点;

        第一次添加需扩容table容量为16,临界值16*0.75=12;以后再扩容,table和临界值都扩大两倍32和24,以此类推;

        当table大小>= 64且一条链上的元素个数超过默认值8,就会树化(红黑树),链表会转换为红黑树,以提高查找效率; 相反地,如果某个红黑树中的节点数减少到小于 6,它会被转换回链表,以节省空间;

HashSet 和 HashMap 的区别:

HashSet:

        是 Java 集合框架中的一个类,它实现了 Set 接口。HashSet 不保证元素的顺序,并且不允许存储重复元素。它是基于 HashMap 实现的,具体来说,HashSet 使用 HashMap 的键来存储元素,而值则使用一个静态的对象(通常是一个 PRESENT 标记),因为 HashSet 只关心元素是否存在于集合中,而不关心它们关联的值。

        使用场景:

                当你需要一个不包含重复元素的集合时,HashSet 是一个很好的选择;

                对于频繁的插入、删除和查找操作,HashSet 提供了高效的性能;

HashMap:

        是 Java 集合框架中的一个类,它实现了 Map 接口。HashMap 存储键值对(key-value pairs),并且允许一个 null 键和多个 null 值。它不保证键值对的顺序,并且基于哈希表(hash table)实现。

        使用场景:

                当你需要一个键值对映射关系,并且需要高效地进行插入、删除和查找操作时,HashMap 是一个很好的选择;

                     它适用于大多数不需要保持插入顺序的场景;

功能差异:

        HashSet 关注的是元素的存在性,不允许重复元素,也不关心元素之间的关联值;

        HashMap 关注的是键值对的映射关系,允许一个 null 键和多个 null 值;

性能相似:

        两者都依赖于哈希表结构,因此在插入、删除和查找操作上具有相似的性能特点;

Hashtable(了解即可):

        基本和HashMap一样,但key和value都不能为null,否则会抛出NullPointerExceptioon异常;        

        是线程安全的;

        它是一个更古老的类,最早出现在 Java 1.0 中。

        历史原因:

     Hashtable 是基于早期的 Java 设计理念,当时的设计目标是提供一种线程安全的哈希表实现,而不允许 null 键和值是为了简化内部实现和避免潜在的并发问题;

                Hashtable 最初设计时,Java 还没有引入泛型(generics),并且对 null 的处理相对简单。为了确保线程安全和简化实现,Hashtable 决定不支持 null 键和值。


http://www.ppmy.cn/news/1560665.html

相关文章

df.groupby([pd.Grouper(freq=‘1M‘, key=‘Date‘), ‘Buyer‘]).sum()

df.groupby([pd.Grouper(freq1M, keyDate), Buyer]).sum() 用于根据特定的时间频率和买家&#xff08;Buyer&#xff09;对 DataFrame 进行分组&#xff0c;然后计算每个分组的总和。下面是对这行代码的逐步解释&#xff1a; df.groupby([...])&#xff1a;这个操作会根据传入的…

基于 GitHub API 的 Issue 和 PR 自动化解决方案

文章目录 摘要引言优化 Issue 和 PR 管理的方法工具选择流程优化 自动化 Issue 和 PR 管理代码逻辑详解获取 Issue 数据为 Issue 添加标签将 Issue 分配给开发者主逻辑 实际运行效果进一步扩展QA 环节总结参考资料 摘要 在开源项目中&#xff0c;Issue 和 Pull Request&#x…

yolo格式数据集转换到coco格式

将YOLO格式数据集转换为COCO格式需要处理图像、标注文件以及生成COCO格式的JSON文件。以下Python代码实现&#xff0c;考虑了各种可能的因素&#xff0c;包括图像尺寸、类别映射、标注框的归一化处理等。 YOLO格式说明 标注文件&#xff1a;每个图像对应一个.txt文件&#xff…

WPF自定义任务栏缩略图

任务栏缩略图预览 在Windows7系统上&#xff0c;微软首次推出任务栏缩略图预览功能。 当鼠标划会任务栏上的程序时&#xff0c;会打开一个预览窗口&#xff0c;可以对整个窗口内容进行预览。 效果如下&#xff1a; 在后面的Windows 8/8.1/10/11系统上&#xff0c;都延续了这…

【MyBatis-Plus 条件构造器】全面解析 Wrapper

在 MyBatis-Plus 中&#xff0c; 条件构造器 是一个强大的工具&#xff0c;能够帮助我们灵活地构建 SQL 查询条件&#xff0c;而无需手写繁琐的 SQL 语句。本文将从基础到高级&#xff0c;带你全面了解条件构造器的使用方法及其链式构造能力。 一、什么是条件构造器&#xff1f…

vim、watch、cp和mv

一、vim使用技巧 vim主配置文件&#xff1a;/etc/vimrc &#xff08;对所有用户都生效&#xff09; vim子配置文件&#xff1a;vim ~/.vimrc (只对当前用户生效&#xff09; 可写入&#xff1a; set nu 显示行号 ts2 tab键长度为两个空格&#xff08;默认为8个空格…

【Rust练习】26.Package and Crate

练习题来自&#xff1a;https://practice-zh.course.rs/crate-module/crate.html 建议在命令行下操作完成本节内容&#xff0c;Windows 11/10 首选 Windows 终端&#xff0c;好看&#xff0c;支持渲染中文字体&#xff0c;缺点是功能太少了&#xff1b;其次推荐 mobaxterm&…

pytorch中nn.Conv2d详解及参数设置原则

文章目录 基础参数1. in_channels (输入通道数)2. out_channels (输出通道数)3. kernel_size (卷积核大小)4. stride (步幅)5. padding (填充)6. dilation (膨胀)7. groups (分组卷积)8. bias (偏置) 如何设置参数&#xff1f;1. **in_channels 和 out_channels&#xff08;输入…