2025.06.07
1. Java 中操作字符串有哪些类型?它们之间有什么区别?
Java 主要有三种可操作“字符序列”的类型:
String
特点:不可变(immutable)、底层基于字符数组
char[]
适用:读多写少的场景,它一旦创建,内容就不可变,保证了线程安全
StringBuilder
特点:可变(mutable)、非线程安全,底层同样是
char[]
,扩容时按oldCapacity * 2 + 2
适用:单线程下大量拼接字符串的场景,效率比
String +
高,比StringBuffer
快
StringBuffer
特点:可变、线程安全(方法上用
synchronized
),同样基于char[]
适用:多线程需要频繁修改字符串的场景,但性能低于
StringBuilder
CharSequence
说明:
String
、StringBuilder
、StringBuffer
等都实现了它,表示一段可读的字符序列
2. String 类的常用方法及其作用
长度与内容
int length()
:返回字符串长度(字符个数)。boolean isEmpty()
:判断字符串是否为空(length() == 0
)。char charAt(int index)
:返回指定下标处的字符,0-based。char[] toCharArray()
:将字符串转换为char[]
。byte[] getBytes()
:按平台默认编码将字符串转换成字节数组。
比较与查找
boolean equals(Object)
:区分大小写比较内容是否相同。boolean equalsIgnoreCase(String)
:忽略大小写比较内容是否相同。int compareTo(String another)
:按字典序比较,返回负/零/正。int indexOf(String/char)
:查找某子串或字符第一次出现的位置,找不到返回-1
。int lastIndexOf(String/char)
:查找子串或字符最后一次出现的位置,找不到返回-1
。boolean contains(CharSequence)
:判断是否包含指定子串。boolean startsWith(String)
:判断是否以指定前缀开始。boolean endsWith(String)
:判断是否以指定后缀结束。
截取与分割
String substring(int beginIndex)
:截取从beginIndex
到末尾的子串。String substring(int beginIndex, int endIndex)
:截取从beginIndex
(含)到endIndex
(不含)的子串。String[] split(String regex)
:按正则表达式拆分,返回字符串数组。String trim()
:去除两端空白字符(space、tab、换行等),不影响中间空格。
替换
String replace(char oldChar, char newChar)
:全局替换字符。String replace(CharSequence target, CharSequence replacement)
:全局替换字符串(不支持正则)。String replaceAll(String regex, String replacement)
:按正则替换,所有匹配均被替换。String replaceFirst(String regex, String replacement)
:按正则替换,仅替换第一个匹配。
大小写 & 格式化
String toLowerCase()
:转为全小写。String toUpperCase()
:转为全大写。String format(String fmt, Object… args)
:按格式化字符串生成新字符串(类似printf
)。
连接与常量池
static String join(CharSequence delimiter, CharSequence… elements)
:将多个序列用delimiter
连接成一个字符串。String intern()
:将字符串加入常量池并返回池中引用;若已存在则返回已有引用,便于节省内存和快速比较。
其它
boolean matches(String regex)
:判断整个字符串是否匹配给定正则。拼接建议:大量拼接时推荐使用
StringBuilder
或StringBuffer
,最后调用toString()
得到新String
。
3. List、Set、Map 之间的区别是什么?
List
特点:有序、允许重复
常用实现:
ArrayList
、LinkedList
适用:需要按下标访问、允许重复元素的场景
Set
特点:无序(或排序)、不允许重复
常用实现:
HashSet
、LinkedHashSet
、TreeSet
适用:需要去重的场景
Map
特点:键值对结构,key 不可重复,value 可重复
常用实现:
HashMap
、LinkedHashMap
、TreeMap
适用:需要快速根据 key 查找 value 的场景
4. HashMap 的实现原理
底层结构:数组 + 链表/红黑树(当单个桶中元素过多时,链表转为红黑树以优化性能)
哈希定位:
hash(key)
→ 扰动后与(capacity - 1)
做位与,定位到数组下标插入:
若目标桶为空,直接插入
否则遍历链表/树,若 key 相同则覆盖 value,否则追加到末尾/树中
扩容:当元素数超过
loadFactor
(默认 0.75)时,容量翻倍,并重新rehash
所有元素查询:同哈希定位过程,遍历桶内链表/树,通过
equals
比较 key,找到则返回对应 value
5. ArrayList 和 LinkedList 的区别
ArrayList
底层结构:动态数组
Object[]
随机访问:O(1)
任意位置插入/删除:O(n)(需要移动元素)
尾部插入/删除:均摊 O(1)
适用:读多写少、需要频繁随机访问的场景
LinkedList
底层结构:双向链表
随机访问:O(n)
任意位置插入/删除:O(1)(只改动指针)
尾部操作:O(1)
适用:插入/删除操作频繁的场景
6. 创建线程池的几种方式
Executors 工厂方法
Executors.newFixedThreadPool(int n)
Executors.newCachedThreadPool()
Executors.newSingleThreadExecutor()
Executors.newScheduledThreadPool(int corePoolSize)
ThreadPoolExecutor 构造
new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), threadFactory, rejectedExecutionHandler );
ForkJoinPool
适合分治任务,内部使用工作窃取算法
Spring 注解方式
@EnableAsync
+ 自定义TaskExecutor
@Scheduled
定时任务线程池
7. 什么是死锁?怎么防止死锁?
死锁:两个或多个线程各自持有对方需要的资源并相互等待,导致都无法继续执行的状态
防止策略:
固定顺序加锁:所有线程按同一顺序请求锁,避免循环等待
尝试加锁(tryLock):使用带超时的
tryLock(timeout)
,超时释放已持有锁再重试锁分离/细化:缩短持锁时间,减少锁竞争
死锁检测与资源剥夺(复杂,少用)
8. Session 和 Cookie 的区别;Session 的工作原理
Cookie
存储位置:客户端(浏览器)
容量:≈4KB
生命周期:可设置过期时间
安全性:易被篡改
Session
存储位置:服务器
容量:受服务器内存/存储限制
生命周期:通常浏览器关闭或超时后失效
安全性:只在客户端保存
sessionId
,相对更安全
Session 工作原理
客户端首次请求时,服务器创建
HttpSession
并生成唯一sessionId
服务器通过
Set-Cookie: JSESSIONID=…
下发给客户端后续请求浏览器携带该 Cookie,服务器根据
sessionId
找到对应HttpSession
在
HttpSession
中存取用户信息、购物车等会话数据
9. 什么是 Spring Boot?Spring Boot 的优点
Spring Boot:基于 Spring 框架的快速开发平台,通过“约定大于配置”和自动化配置简化 Spring 应用搭建
优点:
开箱即用:内嵌 Tomcat/Jetty,无需外部容器
自动配置:根据类路径依赖自动装配常用组件
Starter POMs:一组 Starter 简化依赖管理
生产级监控:Actuator 提供健康检查、指标等
极简配置:
application.properties
/yml
一处配置即可
10. Spring Cloud 的核心组件有哪些?
Spring Cloud Config(配置中心)
Eureka / Consul / Zookeeper(服务注册与发现)
Ribbon(客户端负载均衡)
Feign(声明式 HTTP 客户端,集成 Ribbon)
Hystrix / Resilience4j(断路器)
Zuul / Spring Cloud Gateway(API 网关)
Bus(事件总线,用于广播配置变更)
Sleuth + Zipkin(分布式链路跟踪)
Stream(消息驱动微服务)
11. MyBatis 的一级缓存和二级缓存
一级缓存
作用域:
SqlSession
级别,同会话中相同语句与参数直接从缓存取默认开启;
commit
/rollback
/clearCache
会清空
二级缓存
作用域:Mapper(namespace)级别,跨
SqlSession
共享默认关闭,需要在全局与单个 mapper 中配置
<setting name="cacheEnabled" value="true"/>
与<cache/>
,且返回对象须可序列化
12. 自增表中删除后重启再插入,ID 会是多少?
InnoDB(默认):删除 ID 6、7 后剩 1~5,重启时自增值 =
MAX(id)+1 = 6
,插入的新记录 ID 为 6重启后:InnoDB 会根据表中现有的最大
id
(此例为 5)来重新计算下一个自增值,变成5 + 1 = 6
。未重启:自增计数器仍在内存里,继续累加,所以看到的是 8。
MyISAM:自增计数器保存在磁盘,重启不变,新记录 ID 为 8
13. ACID 是什么?
A (Atomicity,原子性):事务要么全部成功,要么全部失败(回滚)
C (Consistency,一致性):事务执行前后保持数据完整性约束
I (Isolation,隔离性):并发事务互不干扰,可设不同隔离级别
D (Durability,持久性):事务一旦提交,对数据的修改永久保存
14. MySQL 索引是怎么实现的?
B+ 树索引:最常用,非叶子节点存 key 和子节点指针;叶子节点存完整 key + 指向数据行的指针(聚簇索引直接存数据行)
Hash 索引(MEMORY 引擎):通过哈希表实现,等值查询快,范围查询和排序不支持
全文索引:基于倒排索引,支持
MATCH ... AGAINST
R-Tree 索引(MyISAM 空间索引):用于地理空间数据
15. JVM 运行时数据区
程序计数器 (PC Register):存放当前线程所执行字节码的行号指示器
Java 栈 (Stack):每个方法调用时创建的栈帧,存储局部变量、操作数栈、动态链接、方法出口等
本地方法栈 (Native Stack):为执行本地方法服务
堆 (Heap):存放所有对象实例和数组,是 GC 管理的重点区域
方法区 (Method Area):存放类信息、常量、静态变量、即时编译器编译后的代码等(HotSpot 中的 Metaspace)
运行时常量池 (Runtime Constant Pool):方法区的一部分,存放编译期产生的各种字面量和符号引用
直接内存 (Direct Memory):不属于 JVM 内存一部分,通过 NIO 等方式分配,用于高效 I/O
16.服务器被入侵了怎么办?
立即断网隔离
保存证据和日志
修改所有密码(包括数据库、应用等)
评估影响范围
备份核心数据
完全重置系统
重装后及时更新系统补丁
从可信备份恢复数据
加强安全配置和监控
编写事件报告