【Java集合】LinkedList源码深度分析
参考笔记:java LinkedList 源码分析(通俗易懂)_linkedlist源码分析-CSDN博客
目录
1.前言
2.LinkedList简介
3.LinkedList的底层实现
4.LinkedList 与 ArrayList 的对比
4.1 如何选择
4.2 对比图
5.LinkedList 源码Debug
5.1 add(E e)
(1)跳入无参构造
(2) 跳入add方法
(3)跳入linkLast方法
(4)增加第一个元素成功
(5)向链表中添加第二个元素
5.2 remove()
(1)准备工作
(2) 跳入remove()方法
(3)跳入removeFirst()方法
(4)跳入unlinkFirst()方法
(5) 第一个结点被删除
1.前言
本文是对单列集合 List 的实现类之一 LinkedList 的源码解析。对于单列集合 List 的三个最常用的实现类—— ArrayList, Vector, LinkedList ,我对 ArrayList、Vector 的源码解读在另外两篇文章,感兴趣的话可以看看:
【Java集合】ArrayList源码深度分析-CSDN博客
https://blog.csdn.net/m0_55908255/article/details/146886585【Java集合】Vector源码深度分析-CSDN博客
https://blog.csdn.net/m0_55908255/article/details/146949740 注意 : 本文对 LinkedList 源码的解读基于主流的 JDK 8.0 的版本
2.LinkedList简介
① LinkedList 是一种常见的线性表,每一个结点中都存放了下一个结点的地址。 LinkedList 类位于 java.lang.LinkedList 下,其类定义和继承关系图如下:
② 链表可分为单向链表和双向链表
单项链表的每个结点:包含两个值——当前结点的值、下一个结点的地址值(以指向后一个结点)
双向链表的每个结点:包含三个值——前一个结点的地址值(以指向前一个结点)、当前结点的值、下一个结点的地址值(以指向后一个结点)
③ LinkedList 底层实现了双向链表和双端队列的特点
④ 同 ArrayList、Vector 类似,可以向 LinkedList 集合中添加任意元素,包括 null,并且元素允许重复
⑤ 同 ArrayList 一样,LinkedList 也没有实现线程同步,因此 LinkedList 线程不安全
3.LinkedList的底层实现
① LinkedList 的底层维护了一个双向链表。 LinkedList 类中维护了 first、last 属性,见名知意,它们分别指向双向链表的首结点和尾结点。其在源码中的定义如下:
② 链表中的每个结点( Node 对象)中又维护了 prev,next,item 三个属性,item 存放当前节点的值。通过 prev 指向前一个结点,通过 next 指向后一个结点,从而实现双向链表。此处的 Node<E> 类型,实际上是 LinkedList 类中维护的一个静态内部类,如下图所示 :
③ LinkedList 中元素的添加和删除,在底层不是通过数组来完成的,而是通过链表来完成。因此 LinkedList 相对来说增删的效率更高
补充:为什么链表的增删效率比数组高相信学过数据结构的同学都知道,这里我简单提一下
答案:数组如果删除中间的某一个元素可能需要挪动大量的数据,增加亦是如此。而链表只需要修改所删除节点的前后节点的next、prev即可,比较方便
④ 双向链表的示意图如下 : (注意箭头是指向结点整体)
这里我用 Java 来模拟一个简单的双向链表,现在创建三个《诛仙》人物对象——陆雪琪、张小凡、小环,并且让他们形成如下的双向链表关系:
代码如下:
public class demo {public static void main(String[] args) {//演示 : 用java模拟一个简单的双向链表//创建诛仙人物对象Node luxueqi = new Node("陆雪琪"); //第一个结点Node zhangxiaofan = new Node("张小凡"); //第二个结点Node xiaohuan = new Node("小环"); //第三个结点//完成双向链表//从左往右相连接luxueqi.next = zhangxiaofan;zhangxiaofan.next = xiaohuan;//从右往左相连接xiaohuan.prev= zhangxiaofan;zhangxiaofan.prev= luxueqi;//令first指向第一个结点,令last指向最后一个结点Node first = luxueqi;Node last = xiaohuan;//遍历链表(头 ——> 尾)System.out.println("从头-->尾");while (true) {if (first == null) {break;}System.out.println(first); //输出当前对象的信息first = first.next; //更改指向}System.out.println("=====================================");//遍历链表(尾 ——> 头)System.out.println("从尾-->头");while (true) {if (last == null) {break;}System.out.println(last); //输出当前对象的信息last = last.prev; //更改指向}}
}//自定义Node结点
class Node {public Object item; //存放当前结点的数据public Node prev; //指向前一个结点public Node next; //指向后一个结点public Node(Object name) {this.item = name;}public String toString() {return "Node 's name = " + item;}
}
运行结果:
4.LinkedList 与 ArrayList 的对比
4.1 如何选择
① 增删操作多,优先选择 LinkedList ;改查操作多,优先选择 ArrayList
② 实际开发中,往往对集合的改查操作比较多,因此 ArrayList 一般用的较多
③ 根据实际业务需求来选择
④ ArrayList 与 LinkedList 线程均不安全,建议单线程情况下使用
4.2 对比图
5.LinkedList 源码Debug
5.1 add(E e)
用以下代码为演示,进行 Debug 操作:
import java.util.LinkedList;
public class demo {public static void main(String[] args) {LinkedList linkedList = new LinkedList();linkedList.add(11);linkedList.add(141);System.out.println(linkedList);}
}
(1)跳入无参构造
如下图所示:
可以看到, LinkedList 类的无参构造其实什么也没有做,这里只会利用隐藏的 super() 调用父类的无参构造器。因为它底层使用链表实现的,所以不需要创建数组
直接跳出无参构造,可以看到 LinkedList 对象已经初始化完毕, LinkedList 维护的 first、last 属性经过了 默认初始化 ---> 显式初始化 ---> 构造器初始化,最后仍为默认值 null,如下图所示 :
此时 first 和 last 均为 null。所以,链表此时的结构如下图所示:
(2) 跳入add方法
由于我们向链表中添加的元素为 int 类型,所以跳入 add 方法之前会进行自动装箱 int ---> Integer,如下图所示:
自动装箱结束后,跳入 add 方法,如下图所示:
形参列表的 "e" 表示我们当前要添加的元素,所以此时 e = 11 。 add 方法中调用了 linkLast 方法,在 linkLast 方法里面完成了添加元素的操作
(3)跳入linkLast方法
跳入 linkLast 方法,如下图所示:
一步一步来看
首先,Node 是"结点"的意思,就是 Node<E> 类型
其次,本文上面提到说——此时 first == null,last == null。所以,linkLast 方法内,第一步是定义了一个 Node 类型的常指针 ,并令其指向为 last,所以此时
接着,又定义了一个 Node 类型的常量 newNode 。见名知意,"newNode" 就是我们要添加的新结点。那么,为 newNode 初始化的这个带参构造 new Node<>(l,e,null) 是怎么执行的呢?这三个实参分别是干嘛的?
我们追入这个带参构造看个究竟:
可以看到,构造器的三个形参就是 Node 对象的三个属性。所以,对应此处的三个实参, 就是 prev,此时为 null ;e 就是已经装箱好的 11 ;null 就是 next 的值
因此, newNode 引用此时指向的就是一个前后结点均为空,值为 11 的新结点
执行完带参构造,就是 last = newNode,即又令 last 指向了添加的新结点,使得 last 始终指向链表中的最后一个结点,这是典型的链表尾插法
继续向下执行,是一个 if-else 的复合条件语句。判断条件 "l == null" 显然满足,令 first 也指向了该新结点;之后,又令 size 自增 1 (size表示当前链表中结点的个数),modCount 也自增 1(modCount表示链表的修改次数)
(4)增加第一个元素成功
linkLast 执行完毕后,此时的链表结构如下图所示:
接下来,我们可以逐层跳出直到演示类中验证一下上面的链表结构图是否正确。此时链表的状态,如下图所示:
可以看到,first 和 last 确实是指向了同一个结点,并且该结点中 prev = null,next = null,item = 11
(5)向链表中添加第二个元素
向链表中添加第 2 个元素,前面几个步骤都一样,这里就不再赘述了,直接从 linkLast 方法开始说起,如下 :
还是一步一步来看
首先,令 Node 类型的常指针 指向了 last 所指向的结点(即我们前面添加的第一个结点,此时它也为链表中的最后一个结点)
其次,第二个新结点 newNode 进行初始化工作。注意,第一个实参 代表的是新结点的prev,而
此时指向的是第一个结点,因此,这一步实现了——令新节点 newNode 的 prev 指向了第一个结点
接着,执行完带参构造,就是 last = newNode,即又令 last 指向了添加的新结点 newNode ,使得 last 始终指向链表中的最后一个结点,这是典型的链表尾插法
之后,就是 if-else 的判断语句了,此时 指向的是链表中的第一个结点,不为空,所以执行 else 中的语句,l.next = newNode,令第一个结点的 next 指向了新结点
最后,就是更新 size 、modCount
综上,第二次 linkLast 方法执行完毕后,链表结构如下图所示:
🆗,以上就是 LinkedList 的 add(E e) 方法源码分析
5.2 remove()
LinkedList 类的 remove 有三个重载方法:
① remove( ):删除链表的第一个结点
② remove(int index):删除链表中第 index-1 个结点
③ remove(Object o):删除链表中与 o 值匹配的第一个结点
(1)准备工作
用以下代码演示 remove() ,进行 Debug 操作:
import java.util.LinkedList;
public class demo {public static void main(String[] args) {LinkedList linkedList = new LinkedList();linkedList.add(11);linkedList.add(141);linkedList.add(5);System.out.println("添加三个元素后,当前链表 = " + linkedList);linkedList.remove();System.out.println("删除第一个元素后,当前链表 = " + linkedList);}
}
运行结果:
如代码所示,先在链表中加入三个元素:11,141,5 。则在删除元素之前,双向链表的结构如下图所示:
(2) 跳入remove()方法
我们直接在 remove 方法的调用行设置断点跳过去,并跳入 remove 方法,如下图所示 :
(3)跳入removeFirst()方法
removeFirst 方法的源码如下:
首先,它令一个 Node 类型的常指针 f 指向了链表的第一个结点,然后判断首结点是否为空。由于我们一开始就在链表中添加了 3 个元素,所以此处 f 肯定不为空。因此, if 语句中的内容会跳过,执行 return unlinkFirst(f)
(4)跳入unlinkFirst()方法
跳入 unlinkFirst 方法,其源码如下:
一步一步来看
首先,第一条语句不用太关注。取出欲删除结点的 item 值只是为了最后 return 返回,与删除过程本身无关
其次,第二条语句 final Node<E> next = f.next,它令一个 Node 类型的常指针 next 指向了 "第一个结点的next属性所指向的值",即指向了第二个结点,如下图所示 :
接着,执行 f.item = null,f.next = null,置空了第一个结点的 item 和 next ,并且令first 指向了第二个结点,如下图所示 :
继续, 由于 next 现在指向的是第二个结点,不为空,所以接下里要进入 else 语句中。else语句中,next.prev = null,即将第二个结点的 prev 置为 null ,如下图所示 :
最后就是 size - 1,即链表中的结点个数减 1 ;modCount + 1,链表修改次数加 1 ;return elment,返回删除结点其对应的 item 值
(5) 第一个结点被删除
至此,链表中的第一个结点被删除。回顾一下整个流程
① 将第一个结点的 item、next 置为 null
② 将 first 指向了第二个结点
③ 将第二个结点的 prev 值置为 null ,切断其与第一个结点的"联系"
④ 经过①②③,第一个结点被置于链表之外,之后会被 gc垃圾回收器 删除
相关文章:
【Java集合】LinkedList源码深度分析
参考笔记:java LinkedList 源码分析(通俗易懂)_linkedlist源码分析-CSDN博客 目录 1.前言 2.LinkedList简介 3.LinkedList的底层实现 4.LinkedList 与 ArrayList 的对比 4.1 如何选择 4.2 对比图 5.LinkedList 源码Debug 5.1 add(E e) ÿ…...
Java 大视界 -- Java 大数据在智能供应链库存优化与成本控制中的应用策略(172)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
高并发系统架构设计核心要点的结构化提炼【大模型总结】
以下是对高并发系统架构设计核心要点的结构化提炼,结合技术深度与实践视角,以清晰的层次呈现关键策略与实现路径: 一、核心理念重塑 1. 容错优先思维 设计哲学:从"零故障"转向"可恢复性"设计,接…...
【C#深度学习之路】如何使用C#实现Stable Diffusion的文生图功能
【C#深度学习之路】如何使用C#实现Stable Diffusion的文生图功能 项目背景项目实现写在最后项目下载链接 本文为原创文章,若需要转载,请注明出处。 原文地址:https://blog.csdn.net/qq_30270773/article/details/147002073 项目对应的Github地…...
k8s的pod的概述和配置
概念 Pod 容器组 是一个k8s中一个抽象的概念,用于存放一组 container(可包含一个或多个 container 容器,即图上正方体),以及这些 container (容器)的一些共享资源。这些资源包括: 共享存储&…...
RTOS任务句柄的作用
任务句柄(Task Handle)在 FreeRTOS 中的作用详解 任务句柄(TaskHandle_t)是 FreeRTOS 中用于 唯一标识和管理任务 的核心机制,本质是一个指向任务控制块(TCB)的指针。说明即便创建的任务名相同,但对应的任务句柄一定是不同。 它在任务管理、通信、调试中起到关键作用,…...
OpenVLA-OFT——微调VLA的三大关键设计:并行解码、动作分块、连续动作表示以及L1回归目标
前言 25年3.26日,这是一个值得纪念的日子,这一天,我司「七月在线」的定位正式升级为了:具身智能的场景落地与定制开发商 ,后续则从定制开发 逐步过渡到 标准产品化 比如25年q2起,在定制开发之外࿰…...
LocaDate、LocalTime、LocalDateTime
Java8的时间处理 Java的时间处理在早期版本中存在诸多问题(如 java.util.Date 和 java.util.Calendar 的混乱设计),但Java8引入了引入了全新的 java.time包(基于JSR 310),提供了更清晰、线程安全且强大的时…...
哈密尔顿路径(Hamiltonian Path)及相关算法题目
哈密尔顿路径要求访问图中每个顶点恰好一次,通常用于解决旅行商问题(TSP)或状态压缩DP问题。 哈密尔顿路径(Hamiltonian Path)是指在一个图中经过每个顶点恰好一次的路径。如果这条路径的起点和终点相同(即…...
突破传统限制!全新端到端开放词汇多目标跟踪框架OVTR,开启视觉追踪新纪元
在自动驾驶和智能监控等场景中,多目标跟踪(MOT)技术需要应对现实世界中层出不穷的新物体类别。传统方法依赖预定义类别,面对“无人机配件”“新型宠物”等未知目标时往往失效。上海人工智能实验室团队提出的OVTR(Open-…...
Springboot + Vue + WebSocket + Notification实现消息推送功能
实现功能 基于Springboot与Vue架构,首先使用Websocket实现频道订阅,在实现点对点与群发功能后,在前端调用windows自带的消息通知,实现推送功能。 开发环境 Springboot 2.6.7vue 2.6.11socket-client 1.0.0 准备工作 在 Vue.js…...
Linux内核物理内存组织结构
一、系统调用sys_mmap 系统调用mmap用来创建内存映射,把创建内存映射主要的工作委托给do_mmap函数,内核源码文件处理:mm/mmap.c 二、系统调用sys_munmap 1、vma find_vma (mm, start); // 根据起始地址找到要删除的第一个虚拟内存区域 vma 2…...
Redis高级技能进阶
什么是事务的ACID 事务是由一系列对系统中数据进行访问或更新的操作组成的程序执行逻辑单元。这些操作要么都执行,要么都不执行。 为了保证数据库的一致性,在事务处理之前和之后,都应该遵循某些规则,也就是大家耳熟能详的ACID。 …...
PCB设计基础:面向嵌入式工程师的系统性指南
嵌入式系统的性能、稳定性和可靠性,很大程度上依赖于电路硬件的设计质量。在硬件设计中,PCB(Printed Circuit Board)设计是连接系统功能与实际运行的关键一环。本文将从嵌入式工程师的视角,系统性地介绍PCB设计的关键基…...
aspark 配置2
编写Hadoop集群启停脚本 1.建立新文件,编写脚本程序 在hadoop101中操作,在/root/bin下新建文件:myhadoop,输入如下内容: 2.分发执行权限 保存后退出,然后赋予脚本执行权限 [roothadoop101 ~]$ chmod x /r…...
【统计方法】LASSO筛变量
启 比较原始做LASSO包是library(glmnet) 若目标是纯 LASSO 分析,alpha 必须设为 1 标准化数据:LASSO 对特征的尺度敏感,需对数据进行标准化(均值为0,方差为1)。 cv.glmnet获得的lambda.m…...
拥抱健康生活,书写养生新篇
在快节奏的现代生活中,健康愈发成为人们关注的焦点。践行健康养生,并非是一种选择,而是我们对自己和家人应尽的责任。掌握正确的养生之道,不仅能提升生活品质,更能让生命焕发出新的活力。 合理饮食是健康的基石。一…...
Shiro学习(五):Shiro对权限的缓存
一、问题描述 由前边的学习中了解,用户的角色权限一般存储在数据库中,每次进行权限校验时都要从 数据库查询用户的角色权限信息;对数据库来说这样频繁的查询压力太大了,也影响程序的 性能。 Shiro 中执行权限角色校验时࿰…...
QGIS实战系列(六):进阶应用篇——Python 脚本自动化与三维可视化
欢迎来到“QGIS实战系列”的第六期!在前几期中,我们从基础操作到插件应用逐步提升了 QGIS 技能。这一篇,我们将迈入进阶领域,探索如何用 Python 脚本实现自动化,以及如何创建三维可视化效果,让你的 GIS 项目更高效、更立体。 第一步:Python 脚本自动化 QGIS 内置了 Py…...
redis-cpp-cpp如何使用lua脚本
1.前言 我今天要在项目中使用lua脚本,结果搞半天都没有弄明白这个函数怎么调用,而且也似乎很少有redis相关的博客介绍,ai也回答的不准确! 2.正文 今天用一个例子演示一下 下面是lua脚本 const std::string LuaScript R"…...
C# Winform 入门(6)之不同类之间的值传递
承接上一个教程,利用委托事件来进行值传递 声明变量 public static double plx, ply,plxx,plyy;声明委托、事件 //声明委托 //事件 public delegate void transferDistance(double dis); public static transferDistance doTransfer; 直接读取form1中的变量 publ…...
JWT 秘钥的作用机制
JWT 秘钥的作用并不是给前端使用的,而是用于后端服务器内部的一个重要安全机制。 JWT 秘钥的作用 签名与验证: 秘钥主要用于对 JWT(JSON Web Token)进行签名和验证后端使用这个秘钥对令牌进行签名,确保令牌的完整性…...
sun.misc.BASE64Encoder 和 sun.misc.BASE64Decoder包
1. 在将别人的项目导入eclipse之后,出现了"sun.misc.BASE64Encoder找不到jar"的错误,我解决的办法是:右键项目》属性》Java Build Path》jre System Library 》access rules 》resolution选择accessible,下面填上**点击确定即可࿰…...
Java面试黄金宝典34
1. 主键索引底层的实现原理 定义 主键索引是数据库中用于唯一标识表中每一行记录的索引,常见的底层实现是 B 树结构。B 树是一种平衡的多路搜索树,由内部节点和叶子节点组成。内部节点只存储索引键和指向下一层节点的指针,不存储实际数据&am…...
计算机系统---CPU
定义与功能 中央处理器(Central Processing Unit,CPU),是电子计算机的主要设备之一,是计算机的核心部件。CPU是计算机的运算核心和控制核心,负责执行计算机程序中的指令,进行算术运算、逻辑运算…...
AWS云安全基线:构建企业级安全防护体系的完整指南
1. 引言 随着越来越多的企业将其业务和数据迁移到云端,云安全已成为一个不容忽视的关键议题。AWS作为全球领先的云服务提供商,提供了丰富的安全工具和最佳实践。本文将深入探讨如何构建一个全面的AWS云安全基线,以确保您的企业在云环境中的安全性。 2. AWS共享责任模型 在深…...
(三十三)Dart 中使用 Pub 包管理系统与 HTTP 请求教程
Dart 中使用 Pub 包管理系统与 HTTP 请求教程 Pub 包管理系统简介 Pub 是 Dart 和 Flutter 的包管理系统,用于管理项目的依赖。通过 Pub,开发者可以轻松地添加、更新和管理第三方库。 使用 Pub 包管理系统 1. 找到需要的库 访问以下网址,…...
如何实现单例模式?
一、模式定义与核心价值 单例模式(Singleton Pattern)是一种创建型设计模式,保证一个类仅有一个实例,并提供全局访问点。其核心价值在于: 资源控制:避免重复创建消耗性资源(如数据库连…...
【51单片机】2-4【I/O口】震动传感器控制继电器
1.硬件 51最小系统继电器模块震动传感器模块 2.软件 #include "reg52.h"sbit vibrate P3^3;//震动传感器DO接到P3.3口 sbit switcher P1^1;//继电器控制端IN接到P1.1void Delay2000ms() //11.0592MHz {unsigned char i, j, k;// _nop_();i 15;j 2;k 235;do{…...
正点原子 迷你 miniSTM32用ST link烧录后程序不运行(已解决)
情况,在程序和配置都没有问题时检查 烧录使用ST linkv2 烧录后有时程序可行,有时不可行 解决方法 加USB供电配合SW烧录 建议直接用USB转串口烧录 不推荐JLINK供电,也不推荐ST linkv2供电...
如何确保MQ消息队列不丢失:Java实现与流程分析
前言 在分布式系统中,消息队列(Message Queue, MQ)是核心组件之一,用于解耦系统、异步处理和削峰填谷。然而,消息的可靠性传递是使用MQ时需要重点考虑的问题。如果消息在传输过程中丢失,可能会导致数据不一…...
Pascal语言的系统监控
Pascal语言的系统监控 引言 在现代计算机系统中,系统监控是确保计算机平稳运行的重要组成部分。无论是个人计算机还是大型服务器,监控系统的性能、资源使用及状态,都是提高系统效率、及时发现问题的关键。Pascal语言作为一种结构化编程语言…...
6.0 使用Qt+ OpenCV+Python加载图片
本例作为python图像处理的入门课程1,使用Qt+ OpenCV+Python加载图片。 主要有如下几个地方需要注意: 1. OpenCV 默认使用 BGR 格式,而 Qt 使用 RGB。显示前需要转换:cv2.cvtColor(img, cv2.COLOR_BGR2RGB),一般使用某个QLabel控件进行显示。 pic = cv2.cvtColor(pic, cv2.C…...
低成本训练垂直领域文娱大模型的技术路径
标题:低成本训练垂直领域文娱大模型的技术路径 内容:1.摘要 在文娱产业快速发展且对智能化需求日益增长的背景下,为降低垂直领域文娱大模型的训练成本,本研究旨在探索低成本训练的有效技术路径。采用对现有开源模型进行微调、利用轻量化模型架构以及优化…...
音视频入门基础:RTP专题(21)——使用Wireshark分析海康网络摄像机RTSP的RTP流
一、引言 使用vlc等播放器可以播放海康网络摄像机的RTSP流: 网络摄像机的RTSP流中,RTSP主要用于控制媒体流的传输,如播放、暂停、停止等操作。RTSP本身并不用于转送媒体流数据,而是会通过PLAY方法使用RTP来传输实际的音视频数据。…...
【Java网络编程详解】
文章目录 前言一、网络编程基础知识1. 什么是网络编程? 二、Java网络编程核心类三、TCP编程实现1. TCP通信原理2. TCP服务器端示例3. TCP客户端示例 四、UDP编程实现1. UDP通信原理2. UDP服务器端示例3. UDP客户端示例 五、使用HttpURLConnection发送HTTP请求1. GET…...
DuckDB系列教程:如何分析Parquet文件
Parquet 是一种强大的、基于列的存储格式,适用于实现更快捷和更高效的数据分析。您可以使用 DuckDB 这种内存型分析数据库来处理 Parquet 文件并运行查询以对其进行分析。 在这篇文章中,我们将逐步介绍如何使用 DuckDB 对存储在 Parquet 文件中的餐厅订单…...
uniapp的v-for不显示或者swiper-item的不显示
今天开发的时候碰见一个问题,在布局的时候发现v-for遍历的时候不显示内容 H5是正常的 但是在小程序就是不显示 最后排查的原因是同一个组件 swiper-item的 v-for不能用相同的名称 比如 <swiper-item v-for"i in 3" :key"i"><image …...
解决LeetCode“使括号有效的最少添加”问题
目录 问题描述 解题思路 复杂度分析 示例分析 暴力替换“不讲码德” 总结 问题描述 给定一个仅由 ( 和 ) 组成的字符串 s,我们需要通过添加最少数量的括号(( 或 ))使得字符串有效。有效字符串需满足: 空字符串是有效的。 …...
黑马点评_知识点
将手机验证码保存到HttpSession中进行验证(感觉已经过时) Controller中的参数有HttpSession,存验证码session.setAttribute(SystemConstants.VERIFY_CODE, code); 其他的都是逻辑代码 Cookie的缺点 什么是Session集群共享问题? …...
2025年渗透测试面试题总结-某腾讯-玄武实验室扩展(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 某腾讯-玄武实验室扩展 一、Web安全基础原理与关联漏洞 1.1 CSRF攻击原理深度解析 1.2 反序列化漏洞…...
管理系统 UI 设计:提升企业办公效率的关键
一、管理系统UI设计的基本原则 管理系统UI设计应遵循一系列基本原则,以确保界面友好、操作便捷、信息直观。这些原则包括: 简洁性:界面应去除冗余元素,保持简洁明了,避免用户迷失在复杂界面中。一致性:界…...
Apache Commons Lang3 中的 `isNotEmpty` 与 `isNotBlank`的区别
前言 在 Java 开发中,字符串的空值(null)、空字符串(“”)和空白字符串(如 " ")的判断是高频需求。Apache Commons Lang3 的 StringUtils 类提供了两个核心方法:isNotEmp…...
WPF 登录页面
效果 项目结构 LoginWindow.xaml <Window x:Class"PrismWpfApp.Views.LoginWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.…...
CExercise_05_1函数_2海伦公式求三角形面积
题目: 键盘录入三个边长(带小数),然后用海伦公式计算三角形的面积(如果它确实是一个三角形的话) 海伦公式求三角形面积: 要求基于下列两个函数完成这个编程题: // 判断abc是否可以组…...
Muduo网络库实现 [十五] - HttpContext模块
目录 设计思路 类的设计 解码过程 模块的实现 私有接口 请求函数 解析函数 公有接口 疑惑点 设计思路 记录每一次请求处理的进度,便于下一次处理。 上下文模块是Http协议模块中最重要的一个模块,他需要记录每一次请求处理的进度,需…...
构建自己的私有 Git 服务器:基于 Gitea 的轻量化部署实战指南
对于个人开发者、小型团队乃至企业来说,将项目代码托管在 GitHub、Gitee 等公共平台虽然方便,但也存在一定的隐私与可控性问题。 搭建一套私有 Git 代码仓库系统,可以实现对源码的完全控制,同时不依赖任何第三方平台,…...
【计科】计算机科学与技术,从离散数学到软件工程,从理学/抽象/科学到工学/具体/技术
【计科】计算机科学与技术,从离散数学到软件工程,从理学/抽象/科学到工学/具体/技术 文章目录 1、发展史与桥梁(离散数学 -> 算法/数据结构 -> 软件工程)2、离散数学(数理逻辑-命题/谓词/集合/函数/关系 -> 代…...
架构与大数据-RabbitMQ和Kafka的技术实现异同及落地场景上的异同
RabbitMQ与Kafka技术实现及场景对比 一、技术实现异同 对比维度RabbitMQKafka核心协议/模型基于 AMQP 协议,支持点对点、发布/订阅、Topic Exchange 等多种消息模式,支持灵活的路由规则基于 发布-订阅模型,…...