许昌市网站建设_网站建设公司_前端工程师_seo优化
2026/1/10 15:42:07 网站建设 项目流程
集合
  • 一、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集合判断一个对象是否相等

  1. 判断两个对象的hashCode是否一样, 如果hashCode一样, 进行equlas()判断
  2. 如果hashCode一样,equals()返回true, 表示是同一个对象
  3. 如果hashCode不一样, 不会判断eqauls() , 不是同一个对象
  4. 如果hashCode一样,但是eqauls() 返回false, 不是同一个对象

(2)List判断两个对象是否相等

调用 对象equlas() 方法判断, 如果equals() 返回true, 表示同一个对象, 与hashCode无关

(4)哈希码值

将集合中元素的值转换成哈希码值。

(5)判断空集合

(6)元素的个数

1.3 ArrayList集合

定义:
ArrayList: 数组结构,查询效率高,对修改(插入元素,删除元素)效率低

public ArrayList():构造一个初始容量为十的空列表

Vector与ArrayList的区别:

  1. Vector是jdk1.0出现的,老版本java使用的集合,注重安全,是线程安全的;

ArrayList是jdk1.2之后使用,注重性能,是非线程安全的.

  1. 当长度扩充时,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的实现原理

  1. 是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。
  2. 当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。
  3. 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)
  1. 如果key不存在, 做添加存在
  2. 如果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; //扩容阈值

  1. 它的底层会调用Key的hashCode()方法得出hash值。
  1. key的hashCode的低16位异或hashCode高16位, 得到的一个hash值

目的: 减少hash碰撞, (key不一样, hashcode值一样, key不一样,hashCode值不一样,但是计算得到下标一样)

  1. null的hash值:0
  2. table数组 在第一次添加元素的时候,进行初始化, resize()
  3. 每次扩容,扩大为原来的的2倍 newCap = oldCap << 1;
  1. 通过哈希表函数/哈希算法,将hash值转换成数组的下标.
  2. 下标位置上如果没有任何元素,就新创建一个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); }
  1. 第二种: 得到map所有value的集合, 但是, 无法通过value得到key
Collection values = map.values(); //使用迭代器 //简写forEach循环 for(Object value:values){ //获取value System.out.println("-value:"+value); }
  1. 得到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大模型学习资源包》免费分享

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询