集合
- 一、List集合
- 1.1 定义
- 1.2 集合的类结构图
- 1.3 ArrayList集合
- 1.4 LinkedList集合
- 二、set集合
- 2.1 简介
- 2.2 HashSet集合
- 2.3 TreeSet集合
- 2.4 LinkedHashSet集合
- 三 、Map集合
- 3.1 定义
- 3.2 HashMap集合
- 3.3 HashMap的遍历
- 四、扩展
- 4.1 Iterator(迭代器)接口
前言:我们学习过数组,即固定长度的,数组长度一旦确定,这个数组最多存放多少个元素确定,无法做到自动扩容的用来存储一组元素的容器。但是,有时候我们不知道需要存储的数据是多少时,就不能够使用数组来存储了,而是使用集合来存储数据。
一、List集合
1.1 定义
1、集合只能存放对象
2、集合与数组的不同在于:集合可变长度,不限制元素的类型,存储任意类类型的数据,也可以限定元素的类型——泛型
3、集合可以自动扩容
1.2 集合的类结构图
集合分为两大体系:
1、Collection接口:存储的单一对象
(1)List接口:可重复,有序(次序,有下标)
(2)Set接口:唯一,无序(次序,没有下标)
2、Map接口:存储的key/value键值对
(1)key任意数据类型,value任意数据类型
(2)key:唯一,value可重复
因此,我们大多数使用集合时是使用Collection接口下的list集合或者set集合。在Collection接口下,有着许多方法提供给我们解决问题,例如:
增删查改:add( ),addAll( ),remove( ),removeAll( ),clear( )
辅助方法:size( ),isEmpty( ),contains( )
(1)增加
(2)删除
(3)对比
两个对象比较:
理论: 两个对象是否是同一个对象: == equals() 都是在比较地址码是否一样,在实际开发中: 两个对象是否是同一个对象: 1. 如果地址码是否一样, 2. 两个对象的属性值是否一样
对自定义的类类型, 重写Object的equlas()方法, 重写hashCode()
(1)Set集合判断一个对象是否相等
- 判断两个对象的hashCode是否一样, 如果hashCode一样, 进行equlas()判断
- 如果hashCode一样,equals()返回true, 表示是同一个对象
- 如果hashCode不一样, 不会判断eqauls() , 不是同一个对象
- 如果hashCode一样,但是eqauls() 返回false, 不是同一个对象
(2)List判断两个对象是否相等
调用 对象equlas() 方法判断, 如果equals() 返回true, 表示同一个对象, 与hashCode无关
(4)哈希码值
将集合中元素的值转换成哈希码值。
(5)判断空集合
(6)元素的个数
1.3 ArrayList集合
定义:
ArrayList: 数组结构,查询效率高,对修改(插入元素,删除元素)效率低
public ArrayList():构造一个初始容量为十的空列表
Vector与ArrayList的区别:
- Vector是jdk1.0出现的,老版本java使用的集合,注重安全,是线程安全的;
ArrayList是jdk1.2之后使用,注重性能,是非线程安全的.
- 当长度扩充时,Vector直接扩充一倍,而ArrayList是扩充50%
ArrayList默认长度为10个,当存满10个时,长度会自动扩充50%
1.4 LinkedList集合
定义:
LinkedList: 双向链表结构,查询效率低,修改效率高
结论:ArrayList集合和LinkedList集合都是Collection接口下的集合,因此,在Collection接口的所有方法中,ArrayList集合和LinkedList集合都适用。
(1)单向链表
查询效率很低:查找某个点,只能头节点一个一个往下找
(2)双向链表
每个节点:既可以往前找,也可以往后找, 提高查询效率
二、set集合
2.1 简介
Set接口没有提供Collection接口额外的方法,但实现Set接口的集合类中的元素是不可重复的。
JDKAPI中所提供的Set集合类常用的有:
HashSet:散列存放(重点)
TreeSet:有序存放(重点)
LinkedHashSet: 有次序
2.2 HashSet集合
(1)HashSet的实现原理
- 是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。
- 当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。
- HashSet的其他操作都是基于HashMap的。
例子:
如何把同一个对象在HashSet集合中存入两次?
代码:
public class HashSetDemo { public static void main(String[] args) { // 创建 HashSet对象 Set set = new HashSet(); //加入元素到 HashSet 中 set.add("F"); set.add("B"); set.add("D"); set.add("E"); set.add("C"); set.add("B");//当添加相同的元素时,因为Set集合的元素时唯一的,所以会覆盖之前的B System.out.println("set 最初的内容:" + set); //删除元素 set.remove("F"); System.out.println("set 被改变之后:" + set); } }结果:
通过上面的例子,我们发现Set的特点是无序的,元素是唯一的,我们放元素的顺序是”F—B—D—E–C”,而获取的顺序是”B-C-D-E-F”,同样我们发现Set集合的元素是唯一的,我们往Set集合放了两个”B”,但是在Set集合中只有一个”B”。
(2)hashCode()和equals()的比较
因为hashCode()和equals()方法的返回值共同决定了两个对象是否相等,所以覆写着两个方法时一般要保证两个方法的返回值保证兼容。
重写hashCode()和equals()方法的基本规则:
1、 如果两个对象通过equals()方法比较时返回true,则两个对象的hashCode()方法返回值应该也相等。
2、 对象中用作equals()比较标准的成员变量(属性),也应该参与到hashCode的计算。
2.3 TreeSet集合
(1) TreeSet实现原理
TreeSet使用红黑树结构对加入的元素进行排序存放,所以放入TreeSet中元素必须是可**“排序”**的。
(2) 可排序的对象
TreeSet可是采用两种方法实现排序:自然排序和定制排序。默认情况,TreeSet采用自然排序。
TreeSet调用调用集合元素的CompareTo()方法,根据该方法的返回值来比较元素之间的大小,然后进行“升序”排列,这种排序方式我们称之为自然排列。
注意:如果想采用自然排序,则要存储的对象所属类必须实现Comparable 接口。该接口只有一个方法public int compareTo(Object obj),必须实现该方法。
compareTo方法的实现规则:
返回 0,表示 this == obj。//则不会添加新对象
返回正数,表示 this> obj //添加到原来对象的右边
返回负数,表示 this < obj // 添加到原来对的左边
例子:
public class Student implements Comparable<Student> { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(String name, int age) { this.name = name; this.age = age; } public Student() { } @Override public String toString() { final StringBuilder sb = new StringBuilder("Student").append('[') .append("name=") .append(name) .append(",age=") .append(age) .append(']'); return sb.toString(); } @Override public int compareTo(Student o) { //根据年龄升序排序 int rs = this.age - o.age; if(rs == 0 ){ if(o == this){ return 0; }else{ return -1; } } return rs; } }public class TreeSetDemo { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); treeSet.add(new Student("张三",21)); treeSet.add(new Student("李四",18)); treeSet.add(new Student("王五",20)); treeSet.add(new Student("李琦",19)); System.out.println(treeSet); } }结果:
(3)定制排序
使用Comparable接口定义排序顺序有局限性:实现此接口的类只能按compareTo()定义的这一种方式排序。
如果需要更加灵活地排序,我们可以自定义(Comparator)比较器,在创建TreeSet集合对象时把我们自定义的比较器传入,则可以TreeSet会按照我们的比较器中定义的规则进行排序。
自定义比较器类,需要实现Comparator接口。Comparator接口只有一个抽象方法需要实现:public int compare(Object a, Object b);
判断规则:
返回 0,表示a == b
返回正数,表示b > b
返回负数,表示a < b
创建TreeSet集合对象时,把自定义比较器对象传入即可,TreeSet会自动按照比较器中的规则进行排序。
例子:
public class TreeSetDemo { public static void main(String[] args) { TreeSet treeSet = new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { Student stu1 = (Student)o1; Student stu2 = (Student)o2; //按照年龄的降序排序 return stu2.getAge() - stu1.getAge() ; } }); treeSet.add(new Student("张三",21)); treeSet.add(new Student("李四",18)); treeSet.add(new Student("王五",20)); treeSet.add(new Student("李琦",19)); System.out.println(treeSet); } }结果:
2.4 LinkedHashSet集合
根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序
LinkedHashSet集合特点:
底层是一个哈希表(数组+链表/红黑树)+链表,多了一条链表(记录元素的存储顺序),保证元素有序遍历的时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet的方法与它父类HashSet方法是一样的
例子:
public static void main(String[] args) { LinkedHashSet set = new LinkedHashSet(); set.add("hello"); set.add("word"); set.add("zhangsan"); set.add("ls"); set.add("zhangsan"); System.out.println(set); }结果:
我们看到set元素输出的顺序与添加元素的顺序是一致的.。如果我们需要迭代的顺序为插入顺序或者访问顺序,并且保证元素的唯一.那么 LinkedHashSet 是需要你首先考虑的。
三 、Map集合
3.1 定义
存储的key/value 键值对, key: 任意数据类型, (实际开发中,key 一般String), value 任意数据类型,
key: 要求唯一的, value可以重复
实现类: HashMap(线程不安全), HashTable(老版本,面试问)(线程安全),TreeMap, Properties(配置文件,key/value 都是String)
如果往Map添加数据, key在Map已存在, 把新添加的数据的value 覆盖Map的对应key的value
Map里面的key可以为null,但是只能有一个,多个的时候,后面的会覆盖前面的
3.2 HashMap集合
(1)数据结构: 哈希表(数组/链表(|红黑树))
JDK1.7(包含1.7)之前: 数组+链表
JDK1.8 (包含1.8)之后, 引入红黑树(提高查询效率): 数组+链表/红黑树
(2)构造方法
(3)常用方法:
添加元素:
put(key,value)
- 如果key不存在, 做添加存在
- 如果key存在, 做的覆盖value
删除: 根据key删除, 返回的被删除的元素的value
Object remove(Object key)清空:
clear()查询: 根据key得到value
Object get(key) //如果key不存在, 返回null V getOrDefault(Object key,V defaultValue)//如果key不存在, 返回你设置defaultValue判断key,value是否存在:
boolean containsKey(Object key) boolean containsValue(Object value)遍历map:
Set keySet() //获取map所有的key Collection values() //获取mpa所有的value Set<Entry对象> entrySet() //获取map的所有的键值对(Entry --jdk1.7, jdk1.8:Node )(4)原理
jdk1.8 : 数组+链表/红黑树
如果某个桶的链表的长度>=8 ,进行转换红黑树, 先判断table[]的长度 >=64,如果大于, 进行红黑树转换, table长度 < 64, 进行扩容, 每次扩容2倍
hashMap扩容: 达到扩容阈值: = 容量 * 加载因子
添加元素
put() 方法:
重要的属性:
Node[] table; //数组
int threshold; //扩容阈值
- 它的底层会调用Key的hashCode()方法得出hash值。
- key的hashCode的低16位异或hashCode高16位, 得到的一个hash值
目的: 减少hash碰撞, (key不一样, hashcode值一样, key不一样,hashCode值不一样,但是计算得到下标一样)
- null的hash值:0
- table数组 在第一次添加元素的时候,进行初始化, resize()
- 每次扩容,扩大为原来的的2倍 newCap = oldCap << 1;
- 通过哈希表函数/哈希算法,将hash值转换成数组的下标.
- 下标位置上如果没有任何元素,就新创建一个Node节点,并添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
3.3 HashMap的遍历
1.第一种: 得到hashMap所有的key集合: ketSet(), 遍历key的set集合, 得到value
//第一种遍历方式 Set keys = map.keySet(); //使用迭代器 //简写forEach循环 for(Object key:keys){ //根据key获取value Object value = map.get(key); System.out.println("key:"+key+"-value:"+value); }- 第二种: 得到map所有value的集合, 但是, 无法通过value得到key
Collection values = map.values(); //使用迭代器 //简写forEach循环 for(Object value:values){ //获取value System.out.println("-value:"+value); }- 得到map的所有key/value 的set集合, entrySet(); 推荐
//Entry: key/value对 Set entrys = map.entrySet(); //使用迭代器 //简写forEach循环 for(Object entryObj : entrys){ Map.Entry entry = (Map.Entry)entryObj; //获取key, value Object key = entry.getKey(); Object value = entry.getValue(); System.out.println("key:"+key+"-value:"+value); }四、扩展
4.1 Iterator(迭代器)接口
(1)Iterator概述
由于集合中存有很多元素,很多时候需要遍历集合中的所有元素,java专门为集合提供了遍历集合的API:迭代器接口
Iterator是专门的迭代输出接口。所谓的迭代输出就是将元素进行判断,判断是否有内容,如果有内容则把内容取出。
Iterator对象称作迭代器,用以方便的实现对集合内元素的遍历操作。
(2)获得Iterator对象
调用集合对象的iterator()方法,可以获得一个与该集合对象关联的迭代器对象。
例如:
List list =newArrayList<>();
Iteratoriterator = list.iterator(); //获得Iterator对象
(3)Iterator的常用方法
Iterator定义如下三个方法:
boolean hasNext(); //判断游标右边是否有元素。如果有返回true,否则false
Object next() ; //返回游标右边的元素并将游标移动到下一个位置
void remove(); //删除游标左面的元素(即next的时候跳过的对象)
注意:迭代方向是单向的,只能从前朝后(Iterator有个专为list集合设计的子接口ListIterator可以实现双向迭代)。
例子:
public class TestIterator { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("abc"); list.add("bcd"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) {// 判断后面是否还有元素 String string = iterator.next(); // 获得下一个元素 System.out.println(string); } } }注意:在用迭代器遍历集合的时候,如果要删除集合中的元素,只能调用迭代器的remove(),禁止调用集合对象的rmove()方法,否则有可能会出现异常:
java.util.ConcurrentModificationException。//并发访问异常
多学一招:
对于List集合,我们知道List集合是有序的,也就是说,它会给每一个元素添加一个下标,那我们可以使用之前我们学过的for循环去遍历List集合,代码如下:
for(int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); }而对于Set集合,我们知道是无序的那我们就不能通过普通for换去获取它们的下标,因为Set元素没有下标,那就是我们不能使用普通for循环来遍历Set集合.
但是我们知道for循环还有一个增强的for循环,对于所有的集合我们可以使用增强for循环来遍历集合:
for(Object ele: list){ System.out.println(ele); }Java开发的就业市场正在经历结构性调整,竞争日益激烈
传统纯业务开发岗位(如仅完成增删改查业务的后端工程师)的需求,特别是入门级岗位,正显著萎缩。随着企业技术需求升级,市场对Java人才的要求已从通用技能转向了更深入的领域经验(如云原生、微服务)或前沿的AI集成能力。这也导致岗位竞争加剧,在一、二线城市,求职者不仅面临技术内卷,还需应对学历与项目经验的高门槛。
大模型为核心的AI领域正展现出前所未有的就业热度与人才红利
2025年,AI相关新发岗位数量同比激增543%,单月增幅最高超过11倍,大模型算法工程师位居热门岗位前列。行业顶尖人才的供需严重失衡,议价能力极强,跳槽薪资涨幅可达30%-50%。值得注意的是,市场并非单纯青睐算法研究员,而是急需能将大模型能力落地于复杂业务系统的工程人才。这使得具备企业级架构思维和复杂系统整合经验的Java工程师,在向“Java+大模型”复合人才转型时拥有独特优势,成为企业竞相争夺的对象,其薪资天花板也远高于传统Java岗位。
说真的,这两年看着身边一个个搞Java、C++、前端、数据、架构的开始卷大模型,挺唏嘘的。大家最开始都是写接口、搞Spring Boot、连数据库、配Redis,稳稳当当过日子。
结果GPT、DeepSeek火了之后,整条线上的人都开始有点慌了,大家都在想:“我是不是要学大模型,不然这饭碗还能保多久?”
先给出最直接的答案:一定要把现有的技术和大模型结合起来,而不是抛弃你们现有技术!掌握AI能力的Java工程师比纯Java岗要吃香的多。
即使现在裁员、降薪、团队解散的比比皆是……但后续的趋势一定是AI应用落地!大模型方向才是实现职业升级、提升薪资待遇的绝佳机遇!
如何学习AGI大模型?
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享**
一、2025最新大模型学习路线
一个明确的学习路线可以帮助新人了解从哪里开始,按照什么顺序学习,以及需要掌握哪些知识点。大模型领域涉及的知识点非常广泛,没有明确的学习路线可能会导致新人感到迷茫,不知道应该专注于哪些内容。
我们把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。
L1级别:AI大模型时代的华丽登场
L1阶段:我们会去了解大模型的基础知识,以及大模型在各个行业的应用和分析;学习理解大模型的核心原理,关键技术,以及大模型应用场景;通过理论原理结合多个项目实战,从提示工程基础到提示工程进阶,掌握Prompt提示工程。
L2级别:AI大模型RAG应用开发工程
L2阶段是我们的AI大模型RAG应用开发工程,我们会去学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。
L3级别:大模型Agent应用架构进阶实践
L3阶段:大模型Agent应用架构进阶实现,我们会去学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造我们自己的Agent智能体;同时还可以学习到包括Coze、Dify在内的可视化工具的使用。
L4级别:大模型微调与私有化部署
L4阶段:大模型的微调和私有化部署,我们会更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调;并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。
整个大模型学习路线L1主要是对大模型的理论基础、生态以及提示词他的一个学习掌握;而L3 L4更多的是通过项目实战来掌握大模型的应用开发,针对以上大模型的学习路线我们也整理了对应的学习视频教程,和配套的学习资料。
二、大模型经典PDF书籍
书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。(书籍含电子版PDF)
三、大模型视频教程
对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识。
四、大模型项目实战
学以致用,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。
五、大模型面试题
面试不仅是技术的较量,更需要充分的准备。
在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享