Java:集合(List、Map、Set)

文章目录

  • 1. Collection集合
    • 1-1. 迭代器遍历方式
    • 1-2. 通过for循环进行遍历
    • 1-3. forEach遍历
  • 2. List集合
    • 2-1. ArrayList底层实现原理
    • 2-2. LinkedList底层实现原理
  • 3. Set集合
    • 3-1. HashSet 底层实现
    • 3-2. LinkedHashSet 底层实现
    • 3-3. TreeSet
  • 4. Collection集合->总结
  • 5. Map集合
    • 5-1. 通过键找值-进行遍历
    • 5-2. 键值对进行遍历
    • 5-3. 通过Lambda表达式进行遍历
    • 5-4. HashMap 底层实现
    • 5-5. LinkedHashMap 底层原理
    • 5-6. TreeMap 底层原理

1. Collection集合

本身为一个接口。
在这里插入图片描述

包括List、Set集合两种。其中List集合添加的元素有序、可重复、有索引,下面有两个实现类,分别为ArrayList、LinkedList。而Set集合添加的元素是无序的、不重复的、无索引的。它的实现类有HashSet、LinkedHashSet、TreeSet,需要注意的是LinkedHashSet中的元素是有序的,TreeSet中的元素是按照大小默认升序进行排序的。

1-1. 迭代器遍历方式

package jh_study;import java.util.*;public class JHStudy {public static void main(String[] args) {Collection<String> c = new ArrayList<>();for (int i = 0; i < 4; i++) {c.add(String.valueOf(i+1));}Iterator<String> iterator = c.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}

通过集合对象".iterator()"获取其迭代器对象,然后通过“迭代器对象.hasNext()”方法来判断是否已经到末尾;没有到末尾的话,可以通过“迭代器对象.next()”获取对应的元素值,不过获取到元素值之后,其对应的索引(或者指针节点)会指向下一个位置

1-2. 通过for循环进行遍历

package jh_study;import java.util.*;public class JHStudy {public static void main(String[] args) {Collection<String> c = new ArrayList<>();for (int i = 0; i < 4; i++) {c.add(String.valueOf(i+1));}for (String s : c) {System.out.println(s);}}
}

这种方式遍历集合,本质上就是迭代器遍历集合的简化写法。

1-3. forEach遍历

在这里插入图片描述

package jh_study;import java.util.*;
import java.util.function.Consumer;public class JHStudy {public static void main(String[] args) {Collection<String> c = new ArrayList<>();for (int i = 0; i < 4; i++) {c.add(String.valueOf(i+1));}// 匿名内部类写法c.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});// 简化c.forEach((e)->{System.out.println(e);});// 再简化c.forEach((e)-> System.out.println(e));// 再简化c.forEach(System.out::println);}
}

Collection是一个接口,因此实现了该接口对应的类都具备其下的方法。

2. List集合

遍历元素方式除了上述三种之外,还可以通过下标索引进行遍历,当然需要使用到for循环

package jh_study;import java.util.*;public class JHStudy {public static void main(String[] args) {List<Integer> l = new ArrayList<>();l.add(12);l.add(0);for (int i = 0; i < l.size(); i++) {System.out.println(l.get(i));}}
}

2-1. ArrayList底层实现原理

底层实现是基于数组实现的,查看源代码可以发现。
在这里插入图片描述
在这里插入图片描述
根据索引查询速度快(查询数据通过地址值和索引进行定位,查询任意数据耗时相同),删除效率低(可能需要把后面很多的数据进行前移),添加效率低(可能需要把后面很多的数据后移,再添加元素;或者也可能需要进行数组扩容。)

ArrayList底层实现原理:
1.利用无参构造器创建的集合,会在底层创建一个默认长度为0的数组;
2.添加第一个元素时,底层会创建一个新的长度为10的数组;
在这里插入图片描述
在这里插入图片描述
3.存满时,会扩容1.5倍;
在这里插入图片描述
在这里插入图片描述

如果一次添加多个元素,1.5倍还放不下,则新创建的数组的长度以实际为准;
在这里插入图片描述

2-2. LinkedList底层实现原理

底层实现是双向链表。
在这里插入图片描述
在这里插入图片描述
LinkedList的应用场景:实现栈(后进先出)、队列(先进先出)。

3. Set集合

正如上述所说,常见的set集合类型有HashSet、LinkedHashSet、TreeSet。其中,HashSet特点为无序、不重复、无索引;LinkedHashSet特点为有序、不重复、无索引;TreeSet特点为升序、不重复、无索引。

package jh_study;import java.util.*;public class JHStudy {public static void main(String[] args) {Set<Integer> set = new HashSet<>();Set<Integer> set1 = new LinkedHashSet<>();Set<Integer> set2 = new TreeSet<>();System.out.println("HashSet集合");set.add(333);set.add(2222);set.add(1111);set.add(2333);System.out.println(set);System.out.println("LinkedHashSet集合");set1.add(333);set1.add(2222);set1.add(1111);set1.add(2333);System.out.println(set1);System.out.println("TreeSet集合");set2.add(333);set2.add(2222);set2.add(1111);set2.add(2333);System.out.println(set2);}
}

在这里插入图片描述

3-1. HashSet 底层实现

关于hash值,就是一个int类型的数值,Java中每一个对象都有一个hash值;Java中所有的对象,都可以通过调用Object类提供的hashCode方法,返回该对象自己的hash值。
hash值的特点:同一个对象多次调用hashCode方法返回的hash值是相同的;不同对象,它们的hash值一般不相同,但是也有可能相同(hash碰撞)。
在这里插入图片描述
HashSet底层原理:是基于hash表实现的,hash表是一种增删改查数据性能都较好的数据结构。jdk8之前hash表的实现是基于数组+链表实现的;jdk8之后hash表的实现是基于数组+链表+红黑树实现的。
jdk8之前的哈希表底层实现为:创建一个默认长度为16的数组,默认加载因子为0.75(也就是当长度为12时,会进行扩容操作,原数组中的元素会添加到新数组当中去);使用元素的哈希值对数组长度求余计算出应存入的位置;判断当前位置是否为null,如果为null直接存入,如果不为null,表示该位置有元素,则调用equals方法进行比较,相等,则不存,不相等,则存入数组,也就是在数组对应的位置上创建链表,元素存入到链表中进行存储。在jdk8之后,当链表长度超过8,并且数组长度大于或等于64时,自动将链表转换为红黑树。
在这里插入图片描述
jdk8之前的Hash表结构。
在这里插入图片描述
jdk8之后的Hash表结构。
如果在HashSet中有两个内容相同但是它们hash值不同,此时如果我们想去重的话,需要重写其hashCode和equals方法。

package jh_study;import java.util.HashSet;
import java.util.Objects;
import java.util.Set;class User{private String name;private Integer age;public User(String name, Integer age) {this.name = name;this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return Objects.equals(name, user.name) && Objects.equals(age, user.age);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}public class JHStudy2 {public static void main(String[] args) {Set<User> users = new HashSet<>();users.add(new User("张三",20));users.add(new User("张三",20));System.out.println(users);}
}

在这里插入图片描述

3-2. LinkedHashSet 底层实现

LinkedHashSet为HashSet的子类,底层实现依旧是基于哈希表(数组、链表、红黑树)实现的。但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
在这里插入图片描述

3-3. TreeSet

在这里插入图片描述

底层实现基于红黑树实现的升序排序(默认情况下),特点是不重复、无索引、可排序(默认升序排序)。如果在TreeSet中存储的数类型为自定义类型(比如Student),此时如果打印输出结果会报错,因此TreeSet类型并不知道通过Student那个属性进行计较,此时可以在Student类下,让其实现Comparable接口,并重写方法compareTo;当然,也可以直接在定义TreeSet类型的变量时,给上参数new Comparator比较器对象,让其实现方法compare。

package jh_study;import java.util.*;public class JHStudy3 {public static void main(String[] args) {Set<Integer> set = new TreeSet<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}});// 简化写法/*Set<Integer> set = new TreeSet<>((a,b)->{return b - a;});*/set.add(3);set.add(1);set.add(2);System.out.println(set);}
}

在这里插入图片描述

如果上述两种都设置了,类对象实现了Comparable接口,定义TreeSet变量时指定了比较器,那么采用就近原则上那个(也就是比较器)来进行排序的。

4. Collection集合->总结

  1. 如果希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据,可以采用ArrayList集合类型(底层实现基于数组,特点是有序、可重复、有索引);
  2. 如果希望记住元素的添加顺序,且增删首尾数据的情况较多,可以采用LinkedList集合类型(底层实现基于双链表,特点是有序、可重复、有索引);
  3. 如果不在意元素顺序,也没有重复元素需要存储,只希望增删查改都快,可以采用HashSet集合类型;(底层实现基于哈希表,特点是无序、不重复、无索引
  4. 如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快,可以采用LinkedHashSet集合类型(底层实现基于哈希表和双链表,特点为有序、不重复、无索引);
  5. 如果要对元素进行排序,也没有重复元素需要存储,且希望增删改查都快,可以采用TreeSet集合类型(底层实现基于红黑树,特点为升序、不重复、无索引);

在这里插入图片描述

5. Map集合

键值对集合,键不能重复,值可以重复。
常见的比如HashMap(无序、不重复、无索引)、TreeMap(有序、不重复、无索引)、LinkedHashMap(按照大小默认升序排序,不重复,无索引)。

package jh_study;import java.util.*;public class JHStudy4 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put(null,null);map.put("张三","男");map.put("李四","女");map.put("嘻嘻1","MyDream");System.out.println(map);// {null=null, 李四=女, 张三=男, 嘻嘻1=MyDream}System.out.println(map.get("张三"));//男 ,获取键对应的值System.out.println(map.get("赵六"));// null ,不存在的键System.out.println(map.containsKey("李四"));// 判断是否存在某个键 true// map.clear();// 清空map中的数据Set<String> set = map.keySet();System.out.println(set);// 获取所有的键 [null, 李四, 张三, 嘻嘻1]System.out.println(map.isEmpty());// 判断map是否为空 falseSystem.out.println(map.values());// 获取map中所有的值 [null, 女, 男, MyDream]System.out.println(map.size());// 获取map的长度 4System.out.println(map.remove("张三"));// 删除某个键,并返回这个键对应的值 男}
}

5-1. 通过键找值-进行遍历

通过Map对象的 keySet() 方法获取对应的键集合,然后通过遍历键集合来获取对应的值。

package jh_study;import java.util.*;public class JHStudy4 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put(null,null);map.put("张三","男");map.put("李四","女");map.put("嘻嘻1","MyDream");map.put("赵六","man");Set<String> keys = map.keySet();for (String key : keys) {System.out.println(key+"->"+map.get(key));}}
}

在这里插入图片描述

5-2. 键值对进行遍历

通过Map对象的 entrySet() 方法获取键值对集合,然后对这个集合进行遍历即可。

package jh_study;import java.util.*;public class JHStudy4 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put(null,null);map.put("张三","男");map.put("李四","女");map.put("嘻嘻1","MyDream");map.put("赵六","man");Set<Map.Entry<String, String>> set = map.entrySet();for (Map.Entry<String, String> entry : set) {System.out.println(entry.getKey()+"=>"+entry.getValue());}}
}

5-3. 通过Lambda表达式进行遍历

package jh_study;import java.util.*;
import java.util.function.BiConsumer;public class JHStudy4 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put(null,null);map.put("张三","男");map.put("李四","女");map.put("嘻嘻1","MyDream");map.put("赵六","man");map.forEach(new BiConsumer<String, String>() {@Overridepublic void accept(String s, String s2) {System.out.println(s+" "+s2);}});// 简化map.forEach((k,v)-> System.out.println(k+" "+v));}
}

在这里插入图片描述

5-4. HashMap 底层实现

HashMap和HashSet的底层实现原理都是一样的,都是基于哈希表实现的。在JDK8之前,其哈希表基于数组+链表;JDK8之后,其哈希表基于数组+链表+红黑树实现。
在这里插入图片描述

5-5. LinkedHashMap 底层原理

LinkedHashMap 和 LinkedHashSet的底层原理是一样的。
在这里插入图片描述
在这里插入图片描述

5-6. TreeMap 底层原理

TreeMap和TreeSet的底层实现原理都是一样的。
在这里插入图片描述
如果要对数据进行排序,也有两种方式,和TreeSet一样,参考代码如下:
方法1:让需要排序的对象数据实现Comparable即可,并重写方法compareTo。

package jh_study;import java.util.*;public class JHStudy4 {public static void main(String[] args) {Map<User4, Integer> map = new TreeMap<>();map.put(new User4("张三",23),0);map.put(new User4("李四",12),1);map.put(new User4("王五",10),2);map.put(new User4("赵六",25),3);System.out.println(map);}
}class User4 implements Comparable<User4>{String name;Integer age;public User4(String name, Integer age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "User4{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(User4 o) {return o.age - this.age;}
}

在这里插入图片描述
方法2:通过比较器,参考代码如下:

package jh_study;import java.util.*;public class JHStudy4 {public static void main(String[] args) {Map<User4, Integer> map = new TreeMap<>(new Comparator<User4>() {@Overridepublic int compare(User4 o1, User4 o2) {return o1.age-o2.age;}});map.put(new User4("张三",23),0);map.put(new User4("李四",12),1);map.put(new User4("王五",10),2);map.put(new User4("赵六",25),3);System.out.println(map);}
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是Apache日志?为什么Apache日志分析很重要?

Apache是全球最受欢迎的Web服务器软件&#xff0c;支持约30.2%的所有活跃网站。凭借其可靠性、灵活性和强大的功能&#xff0c;Apache数十年来一直是互联网的中坚力量。 一、Apache Web服务器的工作原理 Apache Web服务器的工作原理如下&#xff1a; 接收HTTP请求&#xff1…

【再谈设计模式】组合模式~层次构建的多面手

一、引言 在软件开发的世界里&#xff0c;我们经常面临着处理对象之间复杂关系的挑战。如何有效地表示对象的部分 - 整体层次结构&#xff0c;并且能够以一种统一的方式操作这些对象&#xff0c;是一个值得探讨的问题。组合模式&#xff08;Composite Pattern&#xff09;为我们…

论文翻译 | ChunkRAG: Novel LLM-Chunk Filtering Method for RAG Systems

摘要 使用大型语言模型&#xff08;LLM&#xff09;的检索-增强生成&#xff08;RAG&#xff09;系统经常由于检索不相关或松散相关的信息而生成不准确的响应。现有的在文档级别操作的方法无法有效地过滤掉此类内容。我们提出了LLM驱动的块过滤&#xff0c;ChunkRAG&#xff0…

Redis配置文件中 supervised指令

什么是Supervised&#xff1f; supervised模式允许Redis被外部进程管理器监控。通过这个选项&#xff0c;Redis能够在崩溃后自动重启&#xff0c;确保服务的高可用性。常见的进程管理器包括systemd和upstart。 开启方法 vim修改&#xff1a; sudo vi /etc/redis/redis.conf…

Android四大组件——Activity(二)

一、Activity之间传递消息 在&#xff08;一&#xff09;中&#xff0c;我们把数据作为独立的键值对进行传递&#xff0c;那么现在把多条数据打包成一个对象进行传递&#xff1a; 1.假设有一个User类的对象&#xff0c;我们先使用putExtra进行传递 activity_demo06.xml <…

SpringBoot基于Redis+WebSocket 实现账号单设备登录.

引言 在现代应用中&#xff0c;一个账号在多个设备上的同时登录可能带来安全隐患。为了解决这个问题&#xff0c;许多应用实现了单设备登录&#xff0c;确保同一个用户只能在一个设备上登录。当用户在新的设备上登录时&#xff0c;旧设备会被强制下线。 本文将介绍如何使用 Spr…

【架构】从 Socket 的角度认识非阻塞模型

文章目录 前言1. 阻塞模型2. 非阻塞模型2.1 Reactor 模型优势2.2 Reactor 模型劣势 后记 前言 近期看了很多中间件的文章&#xff0c;RocketMQ&#xff0c;Dubbo 这些中间件内部的rpc通信都用的是非阻塞的模型。(Netty)&#xff0c;这里从 Socket 的角度总结一下。 1. 阻塞模…

location和重定向、代理

location匹配的规则和优先级 在nginx当中&#xff0c;匹配的对象一般是URI来匹配 http://192.168.233.62/usr/local/nginx/html/index.html 182.168.233.61/ location匹配的分类&#xff1a; 多个location一旦匹配其中之一&#xff0c;不在匹配其他location 1、精确匹配 …

ragflow连ollama时出现的Bug

ragflow和ollama连接后&#xff0c;已经添加了两个模型但是ragflow仍然一直warn&#xff1a;Please add both embedding model and LLM in Settings &#xff1e; Model providers firstly.这里可能是我一开始拉取的镜像容器太小&#xff0c;容不下当前添加的模型&#xff0c;导…

软件测试面试问答

文章目录 什么是软件&#xff1f;软件测试工程师的工作内容什么是软件测试&#xff1f;软件开发生命周期软件开发的几个阶段软件bug的五个要素Bug的十大要素:软件测试的分类软件测试方法分类单元测试设计测试用例的主要方法什么是测试用例测试用例几大要素你的测试职业发展是什…

python学习笔记—7—变量拼接

1. 字符串的拼接 print(var_1 var_2) print("supercarry" "doinb") name "doinb" sex "man" score "100" print("sex:" sex " name:" name " score:" score) 注意&#xff1a; …

Win10环境vscode+latex+中文快速配置

安装vscodelatex workshop 配置&#xff1a; {"liveServer.settings.donotVerifyTags": true,"liveServer.settings.donotShowInfoMsg": true,"explorer.confirmDelete": false,"files.autoSave": "afterDelay","exp…

AI生成不了复杂前端页面?也许有解决方案了

在2024年&#xff0c;编程成为了人工智能领域最热门的赛道。AI编程技术正以惊人的速度进步&#xff0c;但在生成前端页面方面&#xff0c;AI的能力还是饱受质疑。自从ScriptEcho平台上线以来&#xff0c;我们收到了不少用户的反馈&#xff0c;他们表示&#xff1a;“生成的页面…

【热力学与工程流体力学】流体静力学实验,雷诺实验,沿程阻力实验,丘里流量计流量系数测定,局部阻力系数的测定,稳态平板法测定材料的导热系数λ

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…

360极速浏览器不支持看PDF

360安全浏览器采用的是基于IE内核和Chrome内核的双核浏览器。360极速浏览器是源自Chromium开源项目的浏览器&#xff0c;不但完美融合了IE内核引擎&#xff0c;而且实现了双核引擎的无缝切换。因此在速度上&#xff0c;360极速浏览器的极速体验感更佳。 展示自己的时候要在有优…

【深度学习】深刻理解ViT

ViT&#xff08;Vision Transformer&#xff09;是谷歌研究团队于2020年提出的一种新型图像识别模型&#xff0c;首次将Transformer架构成功应用于计算机视觉任务中。Transformer最初应用于自然语言处理&#xff08;如BERT和GPT&#xff09;&#xff0c;而ViT展示了其在视觉任务…

idea 配置 git .gitignore文件配置

.gitignore 内容 .idea/ *.iml target/ *.class *.log .iml在idea项目里面创建一个.gitignore名字的文件&#xff0c;然后把这个文件提交到git上。我一般是放到.idea同级目录。 我遇到了几种情况这个文件配置了但是不生效的情况 第一种 Git的缓存可能会导致配置不生效。尝试…

Scala的隐式转换

&#xff08;一&#xff09;隐式转换&#xff1a; 编译器 偷偷地&#xff0c;自动地帮我们把一种数据类型转换为另一种类型。例如&#xff1a;int --> double 它有失败的时候(double-->int),有成功的时候。 当它转换失败的时候&#xff0c;我们提供一个工具&#xff0c;让…

Windows安装WSL子系统及docker,以及WSL和docker配置、使用及问题解决

在Windows操作系统中,Ubuntu子系统(也称为Windows Subsystem for Linux, WSL)为开发者提供了一个在Windows环境下运行Linux环境的平台。然而,有时用户在按照Ubuntu子系统或者使用WSL时,可能会遇到各种问题,下面总结一下解决方式。 想要在Windows上安装Docker(实际上是基…

F12抓包01:启动、面板功能介绍、语言设置、前端样式调试

浏览器检查工具通常用来作为浏览器web服务测试过程中&#xff0c;辅助测试、排查问题、定位缺陷的工具。 本文以mac系统下&#xff0c;当前比较常用的Chrome浏览器为例&#xff0c;讲解“检查”工具的常用功能操作方法。 一、打开方式 **1、****鼠标操作&#xff1a;**浏览器…