一、Java 基础
1. JVM 相关
-
Q:什么情况下会发生栈内存溢出? A:就像食堂打饭窗口前排队,队伍太长(方法调用层级太深),或者每个人占的位置太大(局部变量太多),队伍挤不下就会 “溢出”。具体来说,递归调用没终止条件,或者方法里定义超大数组,都会导致栈内存不够用。
-
Q:JVM 的主要组成部分及其作用? A:JVM 像一个工厂,主要部门包括:
- 类加载器:负责把 Java 代码(.class 文件)翻译成工厂能看懂的 “说明书”;
- 内存区域:分配空间放数据(比如堆存对象,栈存方法调用);
- 执行引擎:按说明书干活,执行字节码指令;
- 垃圾回收器:清理工厂里的废品(不再用的对象)。
-
Q:垃圾回收机制和常见收集器? A:GC 就像扫地阿姨,定期清理 “垃圾对象”(没人引用的对象)。常见扫地阿姨有:
- Serial 收集器:单线程打扫,简单粗暴,适合小房间(单 CPU 场景);
- Parallel 收集器:多线程一起扫,效率高,适合大工厂(多核服务器);
- CMS/G1 收集器:更聪明的阿姨,边干活边扫,减少工厂停工时间(低停顿场景)。
2. 多线程相关
-
Q:线程和进程的区别? A:进程像一个独立的车间(比如微信程序),线程是车间里的工人。一个车间可以有多个工人(多线程),共享车间资源(内存、文件),工人干活更轻量(创建销毁更快)。
-
Q:如何实现线程同步? A:比如多个工人同时用一台机器,需要 “排队”:
- synchronized:给机器加锁,谁拿到锁谁用(如
synchronized(this){...}
); - Lock 接口:更灵活的锁,能中途放弃排队(如
ReentrantLock
); - 原子类:比如
AtomicInteger
,保证数字操作不会被打断(类似自动售货机计数)。
- synchronized:给机器加锁,谁拿到锁谁用(如
-
Q:线程池的原理和常用类? A:线程池像一个工人储备库,提前招好工人(创建线程),有任务就派工人干,干完不辞退,下次接着用。常用类:
ThreadPoolExecutor
:最基础的线程池,可自定义参数;Executors工具类
:快速创建常见线程池(如newFixedThreadPool
固定线程数)。
二、数据库
1. MySQL 基础
-
Q:事务的四大特性?隔离级别和默认级别? A:事务像转账操作,必须满足:
- ACID:
- 原子性(要么全成功,要么全失败,比如转账不能只扣钱不进账);
- 一致性(转账前后总金额不变);
- 隔离性(多个转账互不干扰);
- 持久性(成功后永久保存)。 隔离级别(从低到高):读未提交(可能读到脏数据)、读已提交(MySQL 默认)、可重复读、串行化(性能最差但最安全)。
- ACID:
-
Q:乐观锁和悲观锁的区别? A:悲观锁像抢车位,提前占住(加锁),别人不能用;乐观锁像先停车,走的时候检查有没有人动过(版本号对比),适合冲突少的场景(如商品库存更新)。
-
Q:CHAR 和 VARCHAR 的区别? A:CHAR 是固定长度的盒子(如 CHAR (10) 永远占 10 个位置),适合短且固定的数据(如性别);VARCHAR 是可变长度的盒子,数据多长就占多大空间,适合内容不确定的字段(如文章摘要)。
2. 索引相关
-
Q:索引为什么快?底层数据结构? A:索引像字典的目录,比如查 “Java”,直接翻到 J 开头的页,不用逐页找。MySQL 索引底层是 B + 树,数据按顺序排列,查询时像爬树,快速定位。
-
Q:索引失效的原因? A:比如目录被破坏:
- 字段用函数(如
SELECT * FROM user WHERE YEAR(create_time)=2025
); - 模糊查询以通配符开头(如
LIKE '%java'
); - 类型不匹配(如字段是数字,查询时传字符串
'123'
)。
- 字段用函数(如
-
Q:最左前缀匹配原则? A:复合索引(如
idx_name_age
)像按 “姓名 + 年龄” 排序的名单,查询时必须先按姓名查,再按年龄查。如果只查年龄,索引就用不上(除非姓名也在条件里)。
3. Redis 相关
-
Q:Redis 常见数据类型? A:比 MySQL 更灵活的 “抽屉”:
String
:存单个值(如key:value
);List
:存队列(如聊天记录,按顺序存);Hash
:存对象(如用户信息,user:1
包含name
、age
字段);Set
:存不重复的集合(如点赞用户);ZSet
:带分数的集合(如排行榜,按分数排序)。
-
Q:缓存雪崩和穿透怎么解决? A:
- 雪崩:大量缓存同时过期,像超市开门瞬间挤爆。解决:给缓存过期时间加随机值,避免同时失效;
- 穿透:黑客查不存在的数据,像一直敲空门。解决:用布隆过滤器先过滤不存在的 key,或者缓存空结果(短时间)。
-
Q:Redis 内存满了怎么办? A:按规则扔东西,常见策略:
LRU
:扔最久没用的;LFU
:扔用得最少的;Random
:随机扔(不推荐)。
三、框架相关
1. Spring 框架
-
Q:Spring 框架和核心模块? A:Spring 像一个 “万能工具包”,帮你组装程序:
- IoC 容器:自动管理对象创建和依赖(比如你要泡茶,IoC 会自动给你杯子、茶叶);
- AOP:给程序加 “插件”(如日志、事务),不修改原代码;
- 其他模块:Spring MVC(处理 Web 请求)、Spring Data(操作数据库)等。
-
Q:IoC 和 AOP 的理解? A:
- IoC(控制反转):以前你自己找对象(new),现在对象由 Spring 管理,你直接用(像外卖送到家);
- AOP(面向切面编程):比如给所有方法加日志,不用每个方法里写
System.out
,而是像 “切蛋糕” 一样,在方法执行前后统一处理。
-
Q:Spring Bean 的生命周期? A:Bean(对象)的一生:
- 被 Spring 创建;
- 初始化前(调用
@PostConstruct
注解方法); - 初始化(如设置属性、调用
init-method
); - 被使用;
- 销毁前(调用
@PreDestroy
); - 销毁(如容器关闭)。
2. Spring Boot
-
Q:Spring Boot 和 Spring 的区别? A:Spring 像自己组装电脑(需要配置很多东西),Spring Boot 像品牌机,默认配置好常用功能(如自动配置 Tomcat、数据库连接),开箱即用,减少代码量。
-
Q:Spring Boot 自动配置原理? A:启动时,Spring Boot 会扫描 “启动器”(如
spring-boot-starter-web
),根据依赖自动加载对应的配置类(如 Tomcat 配置、MVC 配置),就像你买了 “Web 启动器”,电脑自动装好浏览器、网络驱动。
3. MyBatis
-
**Q:#{} 和 ${} 的区别?** A:`\#{}`是预编译占位符(像`?`),防SQL注入(如`SELECT * FROM user WHERE id=\#{id}`);${}
是直接拼接字符串(如
ORDER BY ${field}`),使用时要小心注入风险(必须确保参数安全)。 -
Q:MyBatis 缓存机制? A:一级缓存(默认开启):像浏览器缓存,同一方法内查相同数据直接取缓存;二级缓存:像全局缓存,不同方法、甚至不同 Mapper 都能共享(需要手动配置
cache
标签)。
四、分布式与微服务
1. RPC 相关
-
Q:RPC 和常见框架? A:RPC 像打电话,让不同电脑上的程序互相调用(比如 A 服务器调 B 服务器的方法)。常见框架:Dubbo、gRPC、Spring Cloud Feign。
-
Q:为什么用 RPC 而不是 HTTP? A:HTTP 像寄信,内容多(JSON/XML)、速度慢;RPC 像打电话,内容更精简(二进制数据)、效率更高,适合内部服务快速调用。
2. Dubbo
-
Q:Dubbo 工作原理和注册中心? A:Dubbo 像中介平台:
- 服务提供者(商家)把服务注册到注册中心(中介);
- 服务消费者(用户)从注册中心查商家地址,直接调用服务;
- 注册中心(如 ZooKeeper)负责记录商家在线状态,相当于 “电话簿”。
-
Q:Dubbo 负载均衡策略? A:多个商家时,决定调用哪个:
- 随机(像抽签);
- 轮询(按顺序轮流);
- 权重(根据商家 “能力” 分配,如配置
weight=100
)。
3. 消息队列
-
Q:为什么用消息队列? A:像快递中转站,解决高峰期拥堵:
- 削峰:订单高峰期,先把请求存队列,慢慢处理;
- 解耦:订单系统和物流系统不直接连,通过队列传递消息,一方挂了不影响另一方。
-
Q:如何保证消息不重复消费? A:给每个消息贴唯一标签(如 UUID),消费时记录已处理的标签,重复消息来了直接忽略(类似快递单号,签收一次后不再处理)。
五、其他高频问题
1. 设计模式
-
Q:项目中用过哪些设计模式? A:比如:
- 单例模式(如全局唯一的配置类,
private static
实例); - 工厂模式(根据参数创建不同的服务类,如
UserServiceFactory.create("admin")
); - 观察者模式(订单状态变化时,自动通知物流系统,类似微信消息推送)。
- 单例模式(如全局唯一的配置类,
-
Q:单一职责和开闭原则? A:
- 单一职责:一个类只干一件事(如
UserService
只处理用户逻辑,不负责日志); - 开闭原则:对扩展开放,对修改关闭(加新功能时不修改原代码,而是新增类,如新增支付方式时,继承
Payment
接口)。
- 单一职责:一个类只干一件事(如
2. 网络编程
-
Q:BIO、NIO、AIO 的区别? A:
- BIO:像排队买票,必须等前面的人买完才轮到你(同步阻塞);
- NIO:像超市收银,你先取号,逛一圈再回来问有没有轮到(同步非阻塞);
- AIO:像外卖,下单后不用管,做好了直接送上门(异步非阻塞)。
-
Q:Netty 为什么比 NIO 好用? A:NIO 是毛坯房,需要自己组装(Selector、Channel 等);Netty 是精装房,封装了底层细节,提供更易用的 API,还解决了 NIO 的 bug(如 epoll 空轮询),适合高并发场景(如聊天服务器)。
3. 权限认证
-
Q:认证和授权的区别? A:认证是 “你是谁”(如账号密码登录),授权是 “你能做什么”(如管理员能删数据,普通用户不能)。
-
Q:JWT 如何实现身份验证? A:JWT 像电子身份证:
- 登录成功后,服务器生成包含用户信息的 JWT 字符串;
- 客户端每次请求带 JWT(如放在 Header);
- 服务器解析 JWT,验证签名是否有效,确认用户身份。
记忆技巧
- 类比生活场景:把技术概念比作 “食堂排队”“快递中转站” 等,更容易联想;
- 抓核心关键词:如事务 ACID、索引 B + 树、JWT “电子身份证”;
- 结合项目经验:回答时穿插实际场景(如 “我们项目用 Redis 缓存商品列表,解决了高峰期查询慢的问题”)。