【面经总结】Java集合 - List

ArrayList

要点

实现机制

数组

扩容机制

初始容量为空列表,第一次插入后扩容成默认大小 10。

添加元素时如果已满,会自动扩容为原始大小的 1.5 倍。

类定义

// 类定义
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  1. 实现了 RandomAccess 接口,支持随机访问。

RandomAccess 是一个标志接口,说明该类支持快速随机访问

  1. 实现了 Cloneable 接口,默认为浅拷贝。
  2. 实现了 Serializable 接口,支持序列化。
  3. 非线程安全:可以使用 Collections.synchronizedList() 包装成线程安全的

数据结构

  1. elementData:对象数组(用于存数据)
  2. size:当前数组长度
  3. DEFAULT_CAPACITY:默认大小
// 默认初始化容量
private static final int DEFAULT_CAPACITY = 10;// 对象数组
transient Object[] elementData;// 数组长度
private int size;

构造方法

  1. 无参构造:默认初始大小(10)
  2. 指定初始大小构造:减少数组的扩容次数,提高性能
public ArrayList() {// 创建一个空数组this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}public ArrayList(int initialCapacity) {if (initialCapacity > 0) {// 根据初始化值创建数组大小this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {// 初始化值为 0 时,创建一个空数组this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);}
}

访问元素

通过下标获取,复杂度 O(1)

// 获取第 index 个元素
public E get(int index) {rangeCheck(index);return elementData(index);
}E elementData(int index) {return (E) elementData[index];
}

添加元素

  1. 尾部添加:直接放在数组最后
  2. 任意位置添加:向后复制后半段来腾出当前位置

默认大小为 10,超过数组大小会触发扩容 1.5 倍。

// 添加元素到数组末尾
public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;
}// 添加元素到任意位置
public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size + 1);  // Increments modCount!!System.arraycopy(elementData, index, elementData, index + 1, size - index);elementData[index] = element;size++;
}

ArrayList 的扩容机制:

private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);
}private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);
}private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;// new = old * 1.5int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}

删除元素

删掉当前位置元素,将后半段向前复制

public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index, numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue;
}

Fail-Fast 机制

使用 modCount 来记录结构发生变化的次数,用来避免并发修改异常。

LinkedList

要点

实现机制

基于双向链表:顺序访问会非常高效,而随机访问效率比较低。

类定义

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  1. 实现了 Deque 接口,也可以被当作队列 Queue 或双端队列 Deque进行操作
  2. 实现了 Cloneable 接口,默认为浅拷贝。
  3. 实现了 Serializable 接口,支持序列化。
  4. 非线程安全:可以使用 Collections.synchronizedList() 包装成线程安全的

数据结构

  1. size:数组长度
  2. first、last:双向链表头尾节点

Node:链表的节点

private static class Node<E> {E item;Node<E> next;Node<E> prev;// ...
}// 链表长度
transient int size = 0;
// 链表头节点
transient Node<E> first;
// 链表尾节点
transient Node<E> last;

序列化

访问元素

通过 size 和 index 判断 Node 是在前半段还是后半段,再遍历链表。时间复杂度 O(n)

public E get(int index) {checkElementIndex(index);return node(index).item;
}Node<E> node(int index) {// assert isElementIndex(index);if (index < (size >> 1)) {Node<E> x = first;for (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;}
}

添加元素

  1. add、addLast:尾插
  2. addFirst:头插
  3. add(index, item):指定位置插入
private void linkFirst(E e) {final Node<E> f = first;final Node<E> newNode = new Node<>(null, e, f);first = newNode;if (f == null) last = newNode;else f.prev = newNode;size++;modCount++;
}void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null) first = newNode;else l.next = newNode;size++;modCount++;
}void linkBefore(E e, Node<E> succ) {// assert succ != null;final Node<E> pred = succ.prev;final Node<E> newNode = new Node<>(pred, e, succ);succ.prev = newNode;if (pred == null) first = newNode;else pred.next = newNode;size++;modCount++;
}public boolean add(E e) {linkLast(e);return true;
}public void add(int index, E element) {checkPositionIndex(index);if (index == size) linkLast(element);else linkBefore(element, node(index));
}public void addFirst(E e) {linkFirst(e);
}public void addLast(E e) {linkLast(e);
}

删除元素

遍历找到要删除的元素节点,然后调用 unlink 方法删除节点

  • 前驱节点指向后继,否则更新头指针;
  • 后继节点指向前驱,否则更新尾指针。
public boolean remove(Object o) {if (o == null) {// 遍历找到要删除的元素节点for (Node<E> x = first; x != null; x = x.next) {if (x.item == null) {unlink(x);return true;}}} else {// 遍历找到要删除的元素节点for (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item)) {unlink(x);return true;}}}return false;
}E unlink(Node<E> x) {// assert x != null;final E element = x.item;final Node<E> next = x.next;final Node<E> prev = x.prev;if (prev == null) {first = next;} else {prev.next = next;x.prev = null;}if (next == null) {last = prev;} else {next.prev = prev;x.next = null;}x.item = null;size--;modCount++;return element;
}

Vector

基于数组实现,特性与ArrayList类似。(不再推荐使用)

线程安全:使用线程同步能力,多线程互斥写入Vector。

全部操作方法都加的有 synchronized 关键字,性能雪崩。

https://blog.csdn.net/weixin_44688973/article/details/119732347

List

Arrays.asList()

  1. 不能转换基本类型的数组:数组会被当成一个对象

  2. 返回的 List 不能增删:返回的不是正常的 ArrayList,没有重写 add 和 remove 方法

  3. 原始数组的修改会影响 List:转换后直接复用了原始的数组

  4. 不能直接使用 Arrays.asList() 来转换基本类型数组。

Arrays.asList() 方法传入的是一个泛型 T 的可变参数,会导致数组整体作为了一个对象成为了 T

public static <T> List<T> asList(T... a) {return new ArrayList<>(a);
}
  1. 返回的 List 不支持增删操作

Arrays.asList() 返回的 List 并不是的 java.util.ArrayList,而是 Arrays 的内部类 ArrayList。没有重写 add 和 remove 方法。

  1. 对原始数组的修改会影响到我们获得的那个 List

Arrays.asList() 转换后直接复用了原始的数组

List.subList()

用途:截取集合中的一部分

问题:

  1. subList 直接引用了原始的 List,而不是一个新的 List,操作会相互影响
  2. 如果原 List 在 subList 操作期间发生了结构修改(增删操作),操作 subList 会抛异常

解决:

  1. 使用新的集合 new ArrayList
  2. 使用 stream 流的 limit 进行操作

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

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

相关文章

Mybatis框架中结果映射resultMap标签方法属性收录

Mybatis框架中结果映射resultMap标签收录 在MyBatis框架中&#xff0c;resultMap 是一种强大的机制&#xff0c;用于将数据库结果集映射到Java对象上。它允许你定义如何将查询结果中的列映射到Java对象的属性上&#xff0c;尤其是当数据库表的字段名与Java对象的属性名不一致时…

Web前端成绩查询:深入解析与实用指南

Web前端成绩查询&#xff1a;深入解析与实用指南 在数字化时代&#xff0c;成绩查询系统已成为学校、培训机构等教育场所不可或缺的一部分。而xWeb前端成绩查询系统&#xff0c;以其高效、便捷的特点&#xff0c;赢得了广大用户的青睐。本文将从四个方面、五个方面、六个方面和…

HTML静态网页成品作业(HTML+CSS)—— 明星吴磊介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

小白月赛96

小白月赛96 a最小胜利数b最小操作次数c最多数组数量 a最小胜利数 最小胜利数 只要有一个超过6次&#xff0c;那么便不可能反败为胜求出两位选手的题目差1&#xff0c;即为反败为胜的条件 ac code #include<iostream> using namespace std; int main(){string a;cin&g…

TCP与UDP案例

udp不会做拆分整合什么的 多大就是多大

【Spine学习08】之短飘,人物头发动效制作思路

上一节说完了跑步的&#xff0c; 这节说头发发型。 基础过程总结&#xff1a; 1.创建骨骼&#xff08;头发需要在上方加一个总骨骼&#xff09; 2.创建网格&#xff08;并绑定黄线&#xff09; 3.绑定权重&#xff08;发根位置的顶点赋予更多总骨骼的权重&#xff09; 4.切换到…

Orange_Pi_AIpro运行蜂鸟RISC-V仿真

Orange_Pi_AIpro运行蜂鸟RISC-V仿真 突发奇想&#xff0c;试一试Orange Pi AIpro上运行蜂鸟RISC-V的仿真。 准备 默认已经有一个Orange Pi AIpro&#xff0c;并且对设备进行一定的初始化配置&#xff0c;可以参考上一篇博文开源硬件初识——Orange Pi AIpro&#xff08;8T&a…

FineReport简单介绍

一、介绍 官网 &#xff1a;FineReport产品简介- FineReport帮助文档 - 全面的报表使用教程和学习资料 报表是以表格、图表的形式来动态展示数据&#xff0c;企业通过报表进行数据分析&#xff0c;进而用于辅助经营管理决策。 FineReport 是一款用于报表制作&#xff0c;分析和…

短视频矩阵系统源码搭建--如何基于各平台原生态坏境做开发

短视频矩阵系统源码搭建是一个涉及多个技术层面的复杂过程&#xff0c;它要求开发者能够理解并利用不同平台的原生环境来开发和部署应用程序。以下是一些基于不同平台原生环境开发短视频矩阵系统的一般步骤和考虑因素&#xff1a; 1.需求分析&#xff1a;首先明确系统需要实现的…

抽奖系统源码_微信抽奖系统PHP源码开源

介绍&#xff1a; 微信抽奖系统源码是一个以php MySQL进行开发的手机抽奖系统源码。用途&#xff1a;适合做推广营销、直播、粉丝抽奖。 功能介绍&#xff1a; 1、后台可以设置每个抽奖用户的抽奖次数,后台添加设置奖品,适和企业和商场搞活动,后台添加用户&#xff0c;才能抽…

[RL9] Rocky Linux 9.4 搭载 PG 16.1

副标题&#xff1a;Rocky Linux 9.4 升级实录&#xff0c;及 PG 16 相关内容 背景 Rocky Linux 9.4 (以下简称 RL) 于5月9日正式发布&#xff0c;本文记录了从 RL 9.3 升级到 9.4 的过程&#xff0c;以及升级前后的一些变化。 之前介绍过 RL 9 的相关内容&#xff0c;请戳&…

学习笔记——网络管理与运维——SNMP(SNMP架构)

三、SNMP架构 1、SNMP结构概述 SNMP被设计为工作在TCP/IP协议族上&#xff0c;基于TCP/IP协议工作&#xff0c;对网络中支持SNMP协议的设备进行管理。所有支持SNMP协议的设备都提供SNMP这个统一界面&#xff0c;使得管理员可以使用统一的操作进行管理&#xff0c;而不必理会设…

个人网站制作 Part 25 添加实时聊天功能 | Web开发项目添加页面缓存

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加实时聊天功能&#x1f528;使用聊天服务&#x1f527;步骤 1: 选择聊天服务&#x1f527;步骤 2: 安装Socket.io&#x1f527;步骤 3: 创建Socket.io服务器 &#x1…

GStreamer 源码编译,在 Clion 下搭建调试环境

前言 最近在学习 GStreamer&#xff0c;官方提供了一些教程&#xff0c;本人希望能够断点调试&#xff0c;以便学习代码逻辑。本文记录如何在 Clion 搭建 GStreamer 源码编译、调试环境 步骤 下载源码 git clone https://gitlab.freedesktop.org/gstreamer/gstreamer.gitCl…

【漏洞复现】英飞达医学影像存档与通信系统 Upload.asmx 任意文件上传漏洞

0x01 产品简介 英飞达 医学影像存档与通信系统 Picture Archiving and Communication System&#xff0c;它是应用在医院影像科室的系统&#xff0c;主要的任务就是把日常产生的各种医学影像(包括核磁&#xff0c;CT&#xff0c;超声&#xff0c;各种X光机&#xff0c;各种红外…

适配不同数据库厂商方案

背景 在对国产化数据有要求的时候&#xff0c;我们会做对 达梦、海量等数据库的配置。 有些SQL 以前没有写成标准SQL&#xff1b; 那么适配的时候怎么办呢&#xff1f;改成标准SQL。 如果不好改呢&#xff1f;比如SQL比较复杂等&#xff0c;需要判断 当前是哪个厂商的数据库…

2024全球边缘计算大会参会企业名单(首批)

6月22日&#xff0c;第九届全球边缘计算大会将在深圳南山区科兴科学园举办&#xff0c;本次大会由边缘计算社区主办&#xff0c;并得到了EMQ、研华科技、网宿科技等单位的大力支持&#xff01;大会邀请了20重磅嘉宾&#xff0c;聚焦边缘计算前沿技术方向和热点趋势。 以下为首批…

HO-VMD-TCN:西储大学轴承故障诊断全流程详解

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理详解 1.数据预处理 2.特征提取 3.故障…

DomoAI让你轻松变身视频达人!支持20s完整视频生成!

账号注册 官网&#xff1a;https://www.domoai.app/zh-Hant/library 功能 支持不同风格的视频类型&#xff0c;支持图片转视频&#xff0c;支持文字转图片&#xff0c;支持静态图片变为动态。 可以切换语言为中文 风格转换 选择不同风格的 支持生成20s&#xff0c;目前接触…

数据预处理 #数据挖掘 #python

数据分析中的预处理步骤是数据分析流程中的重要环节&#xff0c;它的目的是清洗、转换和整理原始数据&#xff0c;以便后续的分析能够准确、有效。预处理通常包括以下几个关键步骤&#xff1a; 数据收集&#xff1a;确定数据来源&#xff0c;可能是数据库、文件、API或网络抓取…