JAVA小知识20:万字详解List与ArrayList

一、集合简介

1.1、什么是集合?

可同时存储多个元素的数据结构就是集合。

1.2、为什么要有集合?

我们可以使用数组同时存储多个元素,但是数组有个弊端。数组创建之后长度就会固定,如需扩容则需要手动扩容,我们需要一个长度可变的新的容器(自动扩容)。

1.3、集合与数组的区别

数组可以存储基本数据类型,也可以存储引用数据类型。但是集合是不能直接存储基本数据类型的,需要把它转化为对应的包装类。

1.4、集合都有什么?

Java 集合框架可以分为两条大的支线:Collection接口与Map接口

  • Collection接口:
    • List接口:有序集合,允许重复元素。
      • ArrayList:基于动态数组实现,支持快速随机访问。
      • LinkedList:基于双向链表实现,适合频繁插入和删除操作。
  • Set接口:无序集合,不允许重复元素。
    • HashSet:基于哈希表实现,元素无序。
    • LinkedHashSet:继承自HashSet,维护插入顺序。
    • TreeSet:基于红黑树实现,元素有序。
  • Queue接口:用于处理先进先出(FIFO)的队列。
    • PriorityQueue:基于堆实现的优先级队列,元素按自然顺序或指定的Comparator排序。
  • Deque接口:双端队列,支持在两端插入和删除元素。
    • ArrayDeque:基于数组实现的双端队列。
    • LinkedList:也实现了Deque接口。
  • Map接口:
    • HashMap:基于哈希表实现,键值对无序。
    • LinkedHashMap:继承自HashMap,维护插入顺序。
    • TreeMap:基于红黑树实现,键值对有序。

我们引用一张图片就能很好地来解释上面的文字:
在这里插入图片描述
今天我们要研究的目标是List这条分支,也是我们开发中最常用的一种集合。

二、List

2.1、List简介

List接口是Java集合框架中的一部分,提供了一组有序的、可重复的元素集合。List接口继承自Collection接口,并在其基础上添加了允许精确控制元素插入位置的操作。

java.util.Collection 接口是 Java 集合框架的根接口之一,它定义了一组通用的方法,用于操作集合中的元素。Collection 接口是 Java 集合框架中所有集合类的共同父接口。

2.2、主要特点

  • 有序性:List接口保证元素的插入顺序,即元素的迭代顺序与插入顺序一致。
  • 可重复性:List接口允许存储重复的元素。
  • 索引访问:List接口提供了基于索引的位置访问元素的能力,类似于数组。

2.3、主要实现类

List接口有几个常用的实现类,每个类有其特定的特点和使用场景:

  • ArrayList:
    • 基于动态数组实现,支持快速随机访问。
    • 适合频繁读取元素的场景。
    • 插入和删除操作相对较慢,尤其是在列表中间插入或删除时。
  • LinkedList:
    • 基于双向链表实现,适合频繁插入和删除操作。
    • 读取速度较慢,因为需要从头遍历到指定位置。
    • 也实现了Deque接口,可以用作双端队列。

2.4、实现类对比

  • ArrayList:适用于随机访问频繁的场景,因为基于数组的实现提供了快速的索引访问。
  • LinkedList:适用于插入和删除操作频繁的场景,因为基于链表的实现提供了更高效的插入和删除操作。

2.5、为什么要用实现类?

在 Java 中,List 是一个接口(java.util.List),而不是一个具体的类。接口本身不能直接实例化为对象,因为它只是一组方法的声明,没有实际的方法实现。所以我们要想实现List,就要做一个向上造型,其中 ArrayList 是 List 接口的子类。将 ArrayList 类的对象赋值给 List 接口的引用,这是一种向上造型操作。这允许各位程序员使用 List 接口的方法来操作 ArrayList 对象,因为 ArrayList 实现了 List 接口,所以它是 List 接口的一个实例。

三、ArrayList

ArrayList 在数组的基础上实现了自动扩容,并且提供了比数组更丰富的预定义方法(各种增删改查),非常方便我们在开发中的使用。

3.1、创建ArrayList

先来看看List的源码:
在这里插入图片描述
我们可以看到List确确实实是继承了Collection,并且他也是一个接口,而且他还有个泛型(关于泛型的知识在java小知识19里面可以看看)。下面我们来看构造方法:
在这里插入图片描述
那我们如何初始化一个ArrayList集合呢?下面有两种方法,我们常用的为方法一。我们可以看到泛型(泛型只能是引用数据类型)里面规定了这个集合只能存储Integer包装类的数据。
在这里插入图片描述

3.2、ArrayList的成员方法

讲完了如何创建一个ArrayList我们来讲讲如何使用ArrayList

方法名描述
add()将元素插入到指定位置的 ArrayList
addAll()添加集合中的所有元素到 ArrayList
clear()删除 ArrayList 中的所有元素
clone()复制一份 ArrayList
contains()判断元素是否在 ArrayList
get()通过索引值获取 ArrayList 中的元素
indexOf()返回 ArrayList 中元素的索引值
removeAll()删除存在于指定集合中的 ArrayList 里的所有元素
remove()删除 ArrayList 里的单个元素
size()返回 ArrayList 里元素数量
isEmpty()判断 ArrayList 是否为空
subList()截取部分 ArrayList 的元素
set()替换 ArrayList 中指定索引的元素
sort()ArrayList 元素进行排序
toArray()ArrayList 转换为数组
toString()ArrayList 转换为字符串
ensureCapacity()设置指定容量大小的 ArrayList
lastIndexOf()返回指定元素在 ArrayList 中最后一次出现的位置
retainAll()保留 ArrayList 中在指定集合中也存在的那些元素
containsAll()查看 ArrayList 是否包含指定集合中的所有元素
trimToSize()ArrayList 中的容量调整为数组中的元素个数
removeRange()删除 ArrayList 中指定索引之间存在的元素
replaceAll()将给定的操作内容替换掉数组中每一个元素
removeIf()删除所有满足特定条件的 ArrayList 元素
forEach()遍历 ArrayList 中每一个元素并执行特定操作

3.3、ArrayList的特性

  1. 动态数组: ArrayList是基于动态数组实现的,它允许存储和操作一个可变数量的元素。数组的容量会自动增长或减少,以适应元素的添加和删除操作,因此无需手动管理数组的大小。
  2. 有序性: ArrayList 是有序集合,它以元素插入的顺序来维护元素的顺序。这意味着可以按照添加元素的顺序来访问和遍历元素。
  3. 允许重复元素: ArrayList 允许存储重复的元素,即同一个元素可以在列表中出现多次。
  4. 随机访问: 由于 ArrayList 基于数组实现,因此它支持随机访问。可以通过索引来直接访问列表中的元素。
  5. 线程不安全: ArrayList 不是线程安全的,这意味着在多线程环境下,如果多个线程同时访问和修改同一个 ArrayList 实例,可能会导致数据不一致或异常。如果需要在多线程环境中使用,可以考虑使用 Collections.synchronizedList() 方法来获得一个线程安全的 ArrayList。
  6. 性能: 由于 ArrayList 支持随机访问,因此对于需要频繁访问元素的场景非常高效。然而,在需要频繁插入或删除元素的情况下,性能可能较差,因为这涉及到数组元素的移动。
  7. 动态扩容: 当 ArrayList 内部数组的容量不足以容纳新元素时,它会自动扩展数组的大小,通常是当前容量的一半。这可以避免频繁的数组重新分配操作,提高了性能。

四、ArrayList成员方法详解

4.1、add():将元素插入到指定位置的 ArrayList 中。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add(1, "Banana"); // 在索引1处插入
System.out.println(list); // 输出: [Apple, Banana]

4.2、addAll():添加集合中的所有元素到 ArrayList 中。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
List<String> moreFruits = Arrays.asList("Banana", "Orange");
list.addAll(moreFruits);
System.out.println(list); // 输出: [Apple, Banana, Orange]

4.3、clear():删除 ArrayList 中的所有元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.clear();
System.out.println(list); // 输出: []

4.4、clone():复制一份 ArrayList。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
ArrayList<String> clonedList = (ArrayList<String>) list.clone();
System.out.println(clonedList); // 输出: [Apple]

4.5、contains():判断元素是否在 ArrayList 中。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
boolean hasApple = list.contains("Apple");
System.out.println(hasApple); // 输出: true

4.6、get():通过索引值获取 ArrayList 中的元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
String fruit = list.get(0);
System.out.println(fruit); // 输出: Apple

4.7、indexOf():返回 ArrayList 中元素的索引值。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
int index = list.indexOf("Banana");
System.out.println(index); // 输出: 1

4.3、removeAll():删除存在于指定集合中的 ArrayList 里的所有元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
List<String> toRemove = Arrays.asList("Banana", "Orange");
list.removeAll(toRemove);
System.out.println(list); // 输出: [Apple]

4.3、remove():删除 ArrayList 里的单个元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.remove("Apple");
System.out.println(list); // 输出: []

4.3、size():返回 ArrayList 里元素数量。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
int size = list.size();
System.out.println(size); // 输出: 1

4.3、isEmpty():判断 ArrayList 是否为空。

ArrayList<String> list = new ArrayList<>();
boolean empty = list.isEmpty();
System.out.println(empty); // 输出: true

4.3、subList():截取部分 ArrayList 的元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
List<String> subList = list.subList(1, 3);
System.out.println(subList); // 输出: [Banana, Orange]

4.3、set():替换 ArrayList 中指定索引的元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.set(0, "Banana");
System.out.println(list); // 输出: [Banana]

4.3、sort():对 ArrayList 元素进行排序。

ArrayList<String> list = new ArrayList<>();
list.add("Banana");
list.add("Apple");
list.sort(String::compareTo);
System.out.println(list); // 输出: [Apple, Banana]

4.3、toArray():将 ArrayList 转换为数组。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
Object[] array = list.toArray();
System.out.println(Arrays.toString(array)); // 输出: [Apple]

4.3、toString():将 ArrayList 转换为字符串。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
String str = list.toString();
System.out.println(str); // 输出: [Apple]

4.3、ensureCapacity():设置指定容量大小的 ArrayList。

ArrayList<String> list = new ArrayList<>();
list.ensureCapacity(100);
list.add("Apple");
System.out.println(list); // 输出: [Apple]

4.3、lastIndexOf():返回指定元素在 ArrayList 中最后一次出现的位置。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Apple");
int lastIndex = list.lastIndexOf("Apple");
System.out.println(lastIndex); // 输出: 2

4.3、retainAll():保留 ArrayList 中在指定集合中也存在的那些元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
List<String> toRetain = Arrays.asList("Apple");
list.retainAll(toRetain);
System.out.println(list); // 输出: [Apple]

4.3、containsAll():查看 ArrayList 是否包含指定集合中的所有元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
List<String> toCheck = Arrays.asList("Apple", "Banana");
boolean containsAll = list.containsAll(toCheck);
System.out.println(containsAll); // 输出: true

4.3、trimToSize():将 ArrayList 中的容量调整为数组中的元素个数。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.trimToSize();
System.out.println(list); // 输出: [Apple]

4.3、removeRange():删除 ArrayList 中指定索引之间存在的元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
list.subList(1, 2).clear(); // 删除索引1到2之间的元素
System.out.println(list); // 输出: [Apple, Orange]

4.3、replaceAll():将给定的操作内容替换掉数组中每一个元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.replaceAll(fruit -> fruit.toUpperCase());
System.out.println(list); // 输出: [APPLE, BANANA]

4.3、removeIf():删除所有满足特定条件的 ArrayList 元素。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.removeIf(fruit -> fruit.startsWith("A"));
System.out.println(list); // 输出: [Banana]

4.3、forEach():遍历 ArrayList 中每一个元素并执行特定操作。

ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.forEach(fruit -> System.out.println(fruit));

五、ArrayList的扩容机制

结合源码我们来讲一下ArrayList的扩容机制

第一步:创建ArrayList对象

首先我们来看一下创建一个ArrayList对象的时候都发生了什么

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
}

ArrayList在底层有一个数组,他的名字叫做elementData,他还有一个成员变量size记录元素的个数。
在这里插入图片描述

如果利用空参的构造方法或者参数为0的情况下,在底层他会默认创建一个长度为0的数组
在这里插入图片描述
在这里插入图片描述
也就是说我们创建一个空参ArrayList对象时候,他的数组长度为0

第二步、添加元素

我们来看看当向ArrayList集合中添加第一个元素时候发生了什么。

当第一次添加元素时,ArrayList 会检查是否需要扩容。在 add 方法中,会调用ensureCapacityInternal 方法来确保容量足够:
在这里插入图片描述

然后我们来看那可能这个ensureCapacityInternal(size + 1); 方法是怎么来保证容量是足够的。

当我们刚刚创建这个ArrayList的时候,他的size值为0,而+1之后参数就为1。
此时,就变成了ensureCapacityInternal(1)
ensureCapacityInternal()方法会调用 ensureExplicitCapacity 来判断是否需要扩容:
在这里插入图片描述

此时又来了一个方法,我们先看看这个calculateCapacity(elementData, minCapacity)都干了什么?

两个参数,一个是底层数组,一个是刚刚传过来的size+1,底层数组在初始化的时候赋值的就是空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,所以满足if条件在这里插入图片描述
而这个DEFAULT_CAPACITY这个常量在源码中的默认值就是10。minCapacity的值为1。所以会返回10

说完了calculateCapacity(elementData, minCapacity)我们接着来看最外层的ensureExplicitCapacity()都干了什么?

在这里插入图片描述

第三步、扩展数组

重点来了!!!可以看到初始数组长度为0,进入到了grow()函数,这个函数就是扩容函数,我们来详细的分析看看。

先上完整代码:
在这里插入图片描述

1、变量初始化

// overflow-conscious code
int oldCapacity = elementData.length;

elementData.length 表示当前 ArrayList 内部数组的长度,即当前容量。
oldCapacity 就是当前数组的长度,即当前 ArrayList的容量。
2、计算新容量

int newCapacity = oldCapacity + (oldCapacity >> 1);

oldCapacity >> 1 是对 oldCapacity 进行右移一位的操作,相当于 oldCapacity / 2。这一步是为了将当前容量增加 50%
newCapacity 就是计算出来的新容量,通常是当前容量的1.5倍。
3、调整新容量

if (newCapacity - minCapacity < 0)
   newCapacity = minCapacity;

这里判断如果 newCapacity(计算后的新容量) 小于 minCapacity(参数),则将newCapacity设置为 minCapacity。这是为了确保扩容后的容量至少能够满足 minCapacity,即确保能够容纳至少 minCapacity 个元素。
4、最大容量限制

if (newCapacity - MAX_ARRAY_SIZE > 0)
   newCapacity = hugeCapacity(minCapacity);

MAX_ARRAY_SIZE 是 ArrayList 内部定义的一个常量,表示数组的最大容量。如果 newCapacity 超过了 MAX_ARRAY_SIZE,则调用hugeCapacity方法进行处理,通常是返回一个较大的合理容量。
5、扩容操作

// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);

·Arrays.copyOf ·方法用于将 ·elementData· 数组扩展到 ·newCapacity ·的大小,并复制原数组的内容到新数组中。这一步实现了真正的扩容操作

关于这个copyof可以看一下我的java小知识18有讲过,这里也直接贴出截图:
在这里插入图片描述

六、关于ArrayList的一些问答

6.1 ArrayList的扩容机制

上面五讲过了

6.2 ArrayList频繁扩容导致性能下降问题

问题:
假设现在需要添加10w条数据,可能时间上很快,不到1s就能添加完,但是这其中ArrayList就会扩容n次,并且重复拷贝n次,这样的操作非常的占用我们的内存开销。
答案:
可以使用有参构造来创建ArrayList,然后添加元素。看下列示例,同样添加10w条数据。

public static void main(String[] args) {
    long t1 = System.currentTimeMillis();
    List<String> list = new ArrayList<>();
    for(int i=0; i<100000; i++) {
        list.add(i+"a");
    }
    long t2 = System.currentTimeMillis();
    System.out.println("方法一运行:"+(t2 - t1)+"毫秒");
    long t3 = System.currentTimeMillis();
    List<String> list2 = new ArrayList<>(100000);
    for(int i=0; i<100000; i++) {
        list2.add(i+"a");
    }
    long t4 = System.currentTimeMillis();
    System.out.println("方法二运行:"+(t4 - t3)+"毫秒");
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计算机视觉】人脸算法之图像处理基础知识(四)

图像的几何变换 图像的几何变换是指在不改变图像内容的前提下对图像的像素进行空间几何变换。主要包括图像的平移变换、镜像变换、缩放和旋转等。 1.插值算法 插值通常用来放缩图像大小&#xff0c;在图像处理中常见的插值算法有最邻近插值法、双线性插值法、二次立方、三次…

中小制造业工厂要不要上MES系统

MES系统的主要功能包括制造数据管理、计划排产管理、生产调度管理、库存管理、质量管理、人力资源管理、工作中心/设备管理、工具工装管理、采购管理、成本管理、项目看板管理、生产过程控制、底层数据集成分析、上层数据集成分解等。通过这些模块&#xff0c;MES为企业打造一个…

【网络安全学习】使用Kali做渗透情报收集-01-<域名信息主机信息>

1.收集开源情报 开源情报(Open Source Intelligence&#xff0c;OSINT)是指从各种公开的渠道中寻找和获取有价值的信息 如&#xff1a;互联网、媒体、社交网络、公共数据库等开源情报具有以下特点&#xff1a; - 丰富性&#xff1a;开源情报涵盖了各种类型和领域的信息 - 可…

【学习】什么样的软件测试项目适合做自动化测试

随着科技的发展和社会的进步, 软件行业也在不断地壮大和发展。在这个过程中&#xff0c;软件测试变得越来越重要&#xff0c;并且成为了保证软件质量的关键环节。而自动化测试作为软件测试的一种方法&#xff0c;在提高测试效率、降低人力成本等方面具有显著的优势。那么什么样…

SpringBoot集成mqtt上下线提醒功能设计

目录 1.首先安装emqx&#xff0c;去官网下载emqx压缩包&#xff0c;并且解压。 2.使用emqx start 命令启动emqx后台管理 3.下载mqttx调试工具&#xff0c;使用mqttx调试mqtt连接。下载地址:MQTTX下载-MQTTX官方版下载,下载完成直接打开&#xff0c;便可进行mqtt连接调试 4.…

超详解——Python 字典详解——小白篇

目录 1. 创建字典 示例&#xff1a; 2. 访问字典中的元素 示例&#xff1a; 3. 修改字典元素 示例&#xff1a; 4. 删除字典元素 示例&#xff1a; 5. 查找元素是否是字典的键 示例&#xff1a; 6. 标准类型操作符 获取字典长度 合并两个字典 7. 常用内置函数 k…

el-table表头修改文字或者背景颜色,通过header-row-style设置样式

方式一 <el-table :header-cell-style"{text-align: center}" />方式二 <template><el-table :header-cell-style"tableHeaderColor" /> </template> <script> export default {methods: {tableHeaderColor ({row, column…

socket收发数据的处理

1. TCP 协议是一种基于数据流的协议 Socket的Receive方法只是把接收缓冲区的数据提取出来,当系统的接收缓冲区为空,Receive方法会被阻塞,直到里面有数据。 Socket的Send方法只是把数据写入到发送缓冲区里,具体的发送过程由操作系统负责。当操作系统的发送缓冲区满了,Send方法会…

基于springboot的大学计算机基础网络教学系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于springboot的大学计算机基础网络教学…

【Pycharm】设置双击打开文件

概要 习惯真可怕。很多小伙伴用习惯了VsCode开发&#xff0c;或者其他一些开发工具&#xff0c;然后某些开发工具是单击目录文件就能打开预览的&#xff0c;而换到pycharm后&#xff0c;发现目录是双击才能打开预览&#xff0c;那么这个用起来就特别不习惯。 解决办法 只需一…

代码随想录-Day31

455. 分发饼干 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都…

swiftui中使用icon图标时,让中间部分不透明显示

在使用了Image(systemName: "plus.circle.fill")这个视图组件后&#xff0c;发现中间的加号竟然是透明的&#xff0c;但是我们想要的是不让它透明&#xff0c;该怎么做呢&#xff1f; 最简单的方式就是给这个图片设置一个白色的背景是不是就好了&#xff1f;我们可以…

Apple - Cocoa Text Architecture Guide

翻译整理自&#xff1a;Cocoa Text Architecture Guide https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009459 文章目录 一、关于 Cocoa 文本系统1、概览大…

web端即时通信技术

web端即时通信技术 对于IM/消息推送这类即时通讯系统而言&#xff0c;系统的关键就是“实时通信”能力。所谓实时通信有以下两层含义 客户端可以主动向服务端发送信息。 当服务端内容发生变化时&#xff0c;服务端可以实时通知客户端。 HTTP局限 Http是客户端/服务器模式中…

AI实践与学习6-RAG流程优化学习

背景 RAG流程很多细节优化点&#xff0c;助力AIGC。 内容 LangChain在RAG功能上的一些能力 多路向量检索 多向量检索器的核心想法是将我们想要用于答案合成的文档与我们想要用于检索的参考文献分开。这允许系统为搜索优化文档的版本&#xff08;例如&#xff0c;摘要&…

LeetCode | 709.转换成小写字母

这道题可以用api也可以自己实现&#xff0c;都不难&#xff0c;大小字母之前相差了32&#xff0c;检查到大写字母时加上32即可 class Solution(object):def toLowerCase(self, s):""":type s: str:rtype: str"""return s.lower()class Solution…

笨蛋学算法之LeetCodeHot100_5_三数之和(Java)

package com.lsy.leetcodehot100;import java.util.ArrayList; import java.util.Arrays; import java.util.List;public class _Hot6_三数之和 {public static List<List<Integer>> threeSum(int[] nums) {//先排序数组Arrays.sort(nums);//存放结果集List<Lis…

QShop商城-短信通知配置

QShop商城-短信通知配置 本系统短信通知配置可选阿里云/腾讯云,二者二选一即可. 阿里云短信 一、登录阿里云短信平台 阿里云短信平台管理地址&#xff1a;https://dysms.console.aliyun.com/dysms.html 二、账户ID和秘钥&#xff08;AccessKeyId 和 AccessKeySecret&#x…

C++初学者指南第一步---2. Hello world

C初学者指南第一步—2. Hello world 目录 C初学者指南第一步---2. Hello world1.源文件 “Hello.cpp”2.编译hello.cpp3.术语4.编译器标志5.不要使用 “using namespace std;” &#xff01; 1.源文件 “Hello.cpp” #include <iostream> // our first program int main…

检索增强生成(RAG)实践:基于LlamaIndex和Qwen1.5搭建智能问答系统

什么是 RAG LLM 会产生误导性的 “幻觉”&#xff0c;依赖的信息可能过时&#xff0c;处理特定知识时效率不高&#xff0c;缺乏专业领域的深度洞察&#xff0c;同时在推理能力上也有所欠缺。 正是在这样的背景下&#xff0c;检索增强生成技术&#xff08;Retrieval-Augmented…