面试必考 | 易错点总结 | 标准答案速记
点击题目展开 / 收起答案
1. ==:基本类型比较值,引用类型比较内存地址
2. equals():默认和 == 一样,但 String、Integer 等包装类重写了该方法,改为比较内容
面试易错点:String 常量池会让 == 看似“有效”,但比较字符串必须用 equals()
1. String:不可变,线程安全,效率低
2. StringBuilder:可变,非线程安全,效率高
3. StringBuffer:可变,线程安全(synchronized),效率低
面试高频:单线程用 StringBuilder,多线程用 StringBuffer
1. 约定:相等的对象必须有相同的 hashCode
2. HashMap / HashSet 先比较 hashCode,再比较 equals
3. 不重写会导致:相等的对象无法在集合中正常存储/获取
面试必背:hashCode 定义相等规则,equals 验证相等
1. final:修饰类(不可继承)、方法(不可重写)、变量(常量)
2. finally:异常处理,一定执行(除非JVM退出)
3. finalize:Object 方法,GC回收前调用(已废弃)
1. ArrayList:数组结构,查询快,增删慢,线程不安全
2. LinkedList:双向链表,查询慢,增删快,占用内存更大
90%场景用 ArrayList;频繁头尾操作用 LinkedList
JDK 1.7:数组 + 链表
JDK 1.8+:数组 + 链表 + 红黑树
链表转红黑树:链表长度 ≥8,数组容量 ≥64
红黑树转链表:节点数 ≤6
默认加载因子 0.75,默认容量 16
1. HashMap:非线程安全,允许 null 键值,效率高
2. Hashtable:线程安全(synchronized),不允许 null,效率低
高并发用 ConcurrentHashMap,不使用 Hashtable
JDK 1.7:分段锁(Segment),锁粒度大
JDK 1.8+:CAS + synchronized,锁粒度为数组节点
效率远高于 Hashtable 和 HashMap+锁
1. 抽象类:extends 单继承,可有构造方法/成员变量,可包含普通方法
2. 接口:implements 多实现,无构造方法,JDK8+ 可默认方法
3. 设计目的:抽象类 is-a,接口 like-a
1. 重载(Overload):同一个类,方法名相同,参数列表不同
2. 重写(Override):子类重写父类,方法名、参数、返回值相同
重写遵循:两同两小一大(方法名参数同、返回值异常更小、权限更大)
1. 进程:资源分配最小单位,独立内存空间
2. 线程:CPU调度最小单位,共享进程内存
3. 进程切换开销大,线程开销小
1. 继承 Thread 类
2. 实现 Runnable 接口(无返回值)
3. 实现 Callable 接口(有返回值+异常)
4. 线程池 Executors/ThreadPoolExecutor
企业开发必须使用线程池,禁止手动创建线程
1. Runnable 无返回值,无法抛出异常
2. Callable 有返回值 Future,可抛出异常
3. Callable 是 JDK1.5 新增
1. sleep:Thread 方法,不释放锁,休眠后自动唤醒
2. wait:Object 方法,释放锁,必须 notify/notifyAll 唤醒
3. wait 必须在同步块中使用
1. NEW(新建)
2. RUNNABLE(可运行)
3. BLOCKED(阻塞)
4. WAITING(等待)
5. TIMED_WAITING(定时等待)
6. TERMINATED(终止)
1. 修饰方法:ACC_SYNCHRONIZED 标识
2. 修饰代码块:monitorenter + monitorexit
3. JDK1.6 后引入偏向锁、轻量级锁、重量级锁
锁升级:无锁 → 偏向锁 → 轻量级锁 → 重量级锁
1. synchronized:JVM 实现,自动释放锁,不可中断、非公平
2. Lock:API 实现,手动解锁,可中断、可公平、可超时
3. Lock 支持条件唤醒 Condition
1. corePoolSize:核心线程数
2. maximumPoolSize:最大线程数
3. keepAliveTime:非核心线程存活时间
4. unit:时间单位
5. workQueue:阻塞队列
6. threadFactory:线程工厂
7. handler:拒绝策略
1. AbortPolicy:直接抛异常(默认)
2. CallerRunsPolicy:调用者线程执行
3. DiscardPolicy:直接丢弃任务
4. DiscardOldestPolicy:丢弃队列最老任务
1. FixedThreadPool 和 SingleThreadPool:队列无界,OOM
2. CachedThreadPool 和 ScheduledThreadPool:最大线程数无界,OOM
必须手动用 ThreadPoolExecutor 定义线程池
作用:线程本地变量,线程间数据隔离
原理:每个线程持有 ThreadLocalMap
key 是弱引用,value 强引用,易内存泄漏
必须手动 remove(),防止内存泄漏
无用对象无法被GC回收,占用内存无法释放
常见场景:静态集合、ThreadLocal、连接未关闭、内部类持有外部类
1. 强引用:绝不回收(OOM也不回收)
2. 软引用:内存不足时回收
3. 弱引用:GC时直接回收
4. 虚引用:必须配合ReferenceQueue,无实际引用
抽象模型,解决多线程可见性、原子性、有序性
核心:主内存 + 线程工作内存
三大特性:可见性、原子性、有序性
作用:保证可见性、禁止指令重排,不保证原子性
原理:内存屏障
使用场景:状态标记量、单例DCL
面试易错:volatile 不能解决 i++ 线程安全问题
1. 饿汉式(线程安全)
2. 懒汉式(线程不安全)
3. 同步方法(低效)
4. 双重校验锁DCL(推荐,volatile)
5. 静态内部类(推荐)
6. 枚举单例(最安全,防反射/序列化)
运行时获取类信息、调用方法、操作属性
核心类:Class、Method、Field、Constructor
应用:Spring/IOC、MyBatis、动态代理
1. JDK:实现接口,基于接口代理
2. Cglib:继承类,基于子类代理
3. JDK 无需依赖,Cglib 需要依赖
4. 无接口用 Cglib,有接口优先 JDK
1. 生成实现目标接口的代理类
2. 调用 InvocationHandler.invoke()
3. 字节码生成 + 类加载
序列化:对象 → 字节序列
反序列化:字节序列 → 对象
必须实现 Serializable 接口
transient 修饰的属性不参与序列化
1. 程序计数器
2. 虚拟机栈
3. 本地方法栈
4. 堆
5. 方法区(元空间 JDK1.8+)
栈:存放基本类型、引用地址,线程私有,自动释放
堆:存放对象实例,线程共享,GC回收
方法区:JVM规范
永久代:JDK1.7及以前实现,受JVM内存限制
元空间:JDK1.8+实现,使用本地内存
1. 类加载检查
2. 分配内存(指针碰撞/空闲列表)
3. 初始化零值
4. 设置对象头
5. 执行 init 方法
1. 对象头:MarkWord + 类型指针
2. 实例数据:属性信息
3. 对齐填充:保证8字节对齐
1. 引用计数法:简单但无法解决循环引用
2. 可达性分析算法:GC Roots 不可达则死亡(主流)
1. 虚拟机栈引用对象
2. 本地方法栈引用对象
3. 类静态属性引用对象
4. 常量引用对象
1. 标记-清除:效率低,内存碎片
2. 标记-复制:效率高,适合新生代,浪费空间
3. 标记-整理:无碎片,适合老年代
1. 新生代:对象存活时间短,复制算法
2. 老年代:对象存活时间长,标记-整理/清除
3. 永久代/元空间:类信息、常量
1. Minor GC:新生代GC,频繁,速度快
2. Major GC:老年代GC,频率低
3. Full GC:整堆收集,频率低,速度慢
新生代:Serial、ParNew、Parallel Scavenge
老年代:Serial Old、Parallel Old、CMS
整堆:G1、ZGC、Shenandoah
1. 初始标记(STW)
2. 并发标记
3. 重新标记(STW)
4. 并发清除
优点:并发收集、低停顿
1. 分代+分区,可预测停顿
2. 整体标记-整理,局部复制
3. 兼顾吞吐量和停顿
加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
准备阶段:为静态变量分配内存并设默认值
初始化阶段:执行静态代码块、赋值静态变量
1. 类加载时先交给父类加载
2. 父类无法加载才自己加载
3. 防止核心类被篡改,保证类安全
加载器:启动类→扩展类→应用类→自定义类加载器
1. 自定义类加载器,重写 loadClass 方法
2. 线程上下文类加载器
3. SPI、JDBC 等使用打破机制
1. 减少GC停顿时间
2. 提高吞吐量
3. 避免OOM、FullGC频繁
-Xms:初始堆
-Xmx:最大堆
-Xmn:新生代大小
-XX:MetaspaceSize:元空间
-XX:+PrintGCDetails:打印GC日志
1. 导出堆转储文件(dump)
2. MAT/JVisualVM 分析大对象
3. 检查内存泄漏、死循环、资源未关闭
4. 调整JVM参数
1. 阻塞IO(BIO)
2. 非阻塞IO(NIO)
3. IO多路复用(NIO)
4. 异步IO(AIO)
BIO:阻塞,一连接一线程,适合短连接、低并发
NIO:非阻塞+多路复用,单线程管理多连接
AIO:异步非阻塞,完成主动通知
1. Channel(通道):双向传输
2. Buffer(缓冲区):数据读写
3. Selector(选择器):IO多路复用
flip():写模式 → 读模式
clear():清空,恢复初始状态
compact():保留未读数据
rewind():重读数据
减少用户态与内核态切换
减少CPU数据拷贝
提升网络传输效率(Kafka、Netty、RocketMQ)
1. 原子性:要么全成功,要么全失败
2. 一致性:执行前后数据一致
3. 隔离性:多事务互不干扰
4. 持久性:提交后永久生效
1. 脏读:读到未提交数据
2. 不可重复读:同一事务两次查询结果不同
3. 幻读:范围查询出现新增数据
1. 读未提交:最低级别,3问题都存在
2. 读已提交:解决脏读(Oracle默认)
3. 可重复读:解决脏读、不可重复读(MySQL默认)
4. 串行化:最高级别,解决所有问题,性能低
主键索引、唯一索引、普通索引、复合索引、全文索引
聚簇索引(主键)、非聚簇索引(二级索引)
B+ 树
叶子节点:存储数据+顺序指针
非叶子节点:只存索引,不存数据
支持范围查询、排序、高效IO
1. 使用函数、运算、类型转换
2. 模糊查询 %开头
3. or 连接非索引字段
4. 复合索引不满足最左前缀
5. MySQL认为全表扫描更快
复合索引从左到右匹配,中断则后面失效
例:索引(a,b,c),where a=? and c=? → 只用到 a
聚簇索引:叶子节点存整行数据,主键默认
非聚簇索引:叶子节点存主键值,需要回表
二级索引查到主键,再去聚簇索引查数据
避免:建立覆盖索引(查询字段都在索引中)
粒度:表锁、行锁、页锁
性质:共享锁(读)、排他锁(写)
算法:记录锁、间隙锁、临键锁
InnoDB:支持事务、行锁、外键、崩溃恢复
MyISAM:不支持事务,表锁,查询快
企业开发必须使用 InnoDB
同一事务范围查询,结果集数量变化
解决:可重复读隔离级别 + 临键锁(Next-Key Lock)
1. SQL优化:避免慢查询、合理索引
2. 结构优化:分库分表、字段设计
3. 架构优化:读写分离、缓存
4. 配置优化:连接数、缓冲池
1. 开启慢查询日志
2. explain 分析执行计划
3. 优化索引、SQL语句
4. 验证优化效果
IOC(控制反转)、AOP(面向切面)
DI(依赖注入)是IOC的实现方式
将对象创建、依赖管理交给Spring容器
降低耦合、提高可维护、方便测试、便于扩展
1. singleton:单例(默认)
2. prototype:多例
3. request:请求
4. session:会话
5. globalSession:全局会话
实例化 → 依赖注入 → 初始化 → 使用 → 销毁
初始化:Aware接口 → BeanPostProcessor前置 → afterPropertiesSet → init-method → 后置处理
1. 构造器注入(Spring推荐,不可变、依赖必选)
2. Setter注入(可选依赖)
3. 字段注入(@Autowired,简单但有隐患)
@Autowired:Spring注解,按类型注入,配合@Qualifier按名称
@Resource:JSR-250,默认按名称,找不到按类型
切面(Aspect)、通知(Advice)、切点(Pointcut)
连接点(JoinPoint)、织入(Weaving)、代理(Proxy)
1. @Before:前置
2. @AfterReturning:返回后
3. @AfterThrowing:异常后
4. @After:最终
5. @Around:环绕(最强)
1. 编程式事务(手动控制,细粒度)
2. 声明式事务(@Transactional,AOP实现,推荐)
1. 非public方法
2. 同类方法调用(无代理)
3. 异常被try-catch吃掉
4. 非运行时异常(默认只回滚RuntimeException/Error)
5. 未被Spring管理
1. 请求→DispatcherServlet
2. 处理器映射器→找到Handler
3. 处理器适配器→执行Handler
4. 返回ModelAndView
5. 视图解析器→渲染视图→响应
@SpringBootApplication 组合3注解:
1. @SpringBootConfiguration
2. @EnableAutoConfiguration(自动配置)
3. @ComponentScan(包扫描)
1. @EnableAutoConfiguration 开启
2. 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
3. @Conditional 条件装配
条件装配,满足条件才注册Bean
常用派生注解:
@ConditionalOnClass、@ConditionalOnBean、@ConditionalOnProperty、@ConditionalOnMissingBean
1. 启动类main方法
2. 初始化SpringApplication
3. 运行run()方法
4. 准备环境、创建容器、注册Bean、自动配置、启动完成
1. @Value
2. @ConfigurationProperties(批量绑定)
3. Environment
4. @PropertySource
C:一致性(所有节点数据一致)
A:可用性(服务可用)
P:分区容错性(网络分区仍可用)
分布式系统必须满足P,只能选择CP或AP
1. 基本可用(允许部分故障)
2. 软状态(允许中间状态)
3. 最终一致性(不要求强一致)
对CAP的延伸,满足高可用
1. Redis(最常用,Redlock)
2. Zookeeper(可靠性高)
3. MySQL(性能低)
1. 纯内存操作
2. 单线程避免锁竞争
3. IO多路复用
4. 高效数据结构
5. 简单通信协议
String、List、Set、ZSet、Hash、HyperLogLog、Geo、Stream
穿透:查不存在数据,直接查库 → 布隆过滤器/缓存空值
击穿:热点key失效 → 互斥锁/永不过期
雪崩:大量key同时失效 → 随机过期时间、集群、降级
1. RDB:快照,全量备份,恢复快,数据可能丢失
2. AOF:日志,增量备份,数据安全,恢复慢
企业:混合持久化(RDB+AOF)
过期删除:惰性删除 + 定期删除
内存淘汰:8种策略,常用:
allkeys-lru(淘汰最少使用)、volatile-lru、noeviction(报错)
异步、解耦、削峰、流量控制
1. 消息重复消费:幂等性
2. 消息丢失:生产/存储/消费确认
3. 消息堆积:优化消费者、扩容、重试
1. 单一职责
2. 开闭原则(对扩展开放,修改关闭)
3. 里氏替换
4. 接口隔离
5. 依赖倒置
6. 迪米特法则
创建型:单例、工厂、建造者、原型
结构型:代理、适配器、装饰器、外观
行为型:观察者、策略、模板、迭代器
1. 唯一索引
2. 令牌机制(Token)
3. 悲观锁/乐观锁
4. 分布式锁
5. 状态机
1. 前端:缓存、限流、静态资源
2. 网关:路由、限流、熔断
3. 服务:无状态、集群、异步、池化
4. 数据:缓存、分库分表、读写分离
注册中心、配置中心、服务网关、服务调用、熔断降级、链路追踪
1. 查看日志(系统/应用)
2. 检查服务器(CPU/内存/磁盘/网络)
3. 检查中间件(DB/Redis/MQ)
4. 降级、熔断、重启应急
5. 定位根因,解决+复盘