跳到正文
Joeplover
学习笔记·2026-06-21·约 6 分钟阅读

Java 面试题整合版

Java 基础、集合、并发、JVM、Spring 等高频面试题整理。

Java 面试

Java 面试题(整合版)

整合自 [[Java笔记]] 相关主题:[[设计模式]] | [[网络基础]]


一、Java 基础

1. == 和 equals() 区别

==:
  - 基本类型 → 比较值
  - 引用类型 → 比较地址
equals():
  - 默认(Object)→ 比较地址
  - String、Integer 等重写过 → 比较内容

2. 为什么重写 equals() 必须重写 hashCode()

HashMap/HashSet 的工作原理:
  1. 先 hashCode() 定位桶
  2. 再 equals() 判断是否相同
如果 equals() 相同但 hashCode() 不同 → 同一个对象会放进不同桶 → 出现重复

3. String、StringBuilder、StringBuffer

可变线程安全性能
String❌ 不可变✅拼接慢(创建新对象)
StringBuilder✅❌高
StringBuffer✅✅中

4. final / finally / finalize

  • final:修饰类(不可继承)、方法(不可重写)、变量(不可变)
  • finally:try 后的代码块,通常一定执行
  • finalize:Object 方法,GC 前调用(已废弃,别用)

5. 重载 vs 重写

重载:同类、同名、参数不同 → 编译时多态
重写:父子类、签名相同 → 运行时多态

6. 三大特性

  • 封装:隐藏内部实现,暴露接口
  • 继承:复用父类能力(is-a)
  • 多态:同一个方法在不同对象上表现不同(父类引用指向子类对象)

7. 抽象类 vs 接口

抽象类接口
构造方法✅❌
成员变量可以有常量(static final)
方法实现可以有普通方法JDK8+ 可以有 default/static
单继承一个类只能继承一个一个类可实现多个

8. 异常体系

Throwable
├── Error(系统级,OOM、StackOverflow,不用处理)
└── Exception
    ├── Checked(编译时异常,必须 try-catch,如 IOException)
    └── Unchecked(运行时异常,不用显式处理,如 NPE)

9. ArrayList vs LinkedList

ArrayListLinkedList
底层动态数组双向链表
随机查O(1) ✅ 快O(n) ❌ 慢
尾部插O(1)O(1)
中间插O(n) 搬数据O(1) 但需先查位置
内存紧凑节点额外开销

10. 手写字符串反转(双指针)

public static String reverse(String str) {
    if (str == null || str.length() <= 1) return str;
    char[] chars = str.toCharArray();
    int left = 0, right = chars.length - 1;
    while (left < right) {
        char tmp = chars[left];
        chars[left++] = chars[right];
        chars[right--] = tmp;
    }
    return new String(chars);
}

二、Java 高级

11. HashMap 底层

JDK7: 数组 + 链表(头插法)→ 并发扩容可能死循环
JDK8: 数组 + 链表 + 红黑树(尾插法)

put 流程:
  1. hash(key) 定位桶
  2. 桶空 → 直接插入
  3. 桶非空 → 比较 key,相同覆盖,不同链表/红黑树追加
  4. 超过阈值(8)且数组≥64 → 链表树化
  5. 超过负载因子 → 扩容 2 倍

12. ConcurrentHashMap

JDK7: Segment 分段锁(分段数组,每段一把锁)
JDK8: CAS + synchronized(锁桶头节点,粒度更细)
       读操作不加锁,写操作对桶加锁

13. 线程池参数

ThreadPoolExecutor(
    corePoolSize,        // 核心线程数
    maximumPoolSize,     // 最大线程数
    keepAliveTime,       // 非核心线程空闲存活时间
    workQueue,           // 阻塞队列
    threadFactory,       // 线程工厂
    handler              // 拒绝策略
)

任务执行流程:

1. 线程 < corePoolSize     → 新建线程执行
2. 线程 ≥ corePoolSize     → 入队列
3. 队列满 & 线程 < max     → 新建非核心线程
4. 队列满 & 线程 = max     → 拒绝策略

拒绝策略:

  • AbortPolicy(默认)→ 抛异常
  • CallerRunsPolicy → 调用线程自己执行
  • DiscardPolicy → 静默丢弃
  • DiscardOldestPolicy → 丢弃最老的任务

14. JMM 三大特性

原子性:synchronized、Lock、Atomic 类保证
可见性:volatile、synchronized 保证(直接写主存)
有序性:volatile(禁止重排)、synchronized(同一锁内串行)

15. DCL 单例

class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {           // 1. 第一次检查
            synchronized (Singleton.class) {
                if (instance == null) {   // 2. 第二次检查
                    instance = new Singleton(); // 3. 必须 volatile!
                }
            }
        }
        return instance;
    }
}

为什么要 volatile: new Singleton() 不是原子操作:

  1. 分配内存
  2. 初始化对象 ← 这两步可能重排
  3. 引用赋值 → 不加 volatile 可能拿到"半初始化"的对象

16. 深拷贝 / 浅拷贝

引用拷贝:b = a          → 同一个对象
浅拷贝:  b = a.clone()  → 新对象,内部引用相同
深拷贝:  手动递归复制    → 从外到内全部独立

三、Spring

17. IOC / AOP

IOC(控制反转):对象创建由 Spring 容器管理,不用自己 new
DI(依赖注入):IOC 的实现方式,运行时注入依赖
AOP(面向切面):把日志/事务/鉴权从业务代码抽离

18. Bean 生命周期

1. 实例化
2. 属性填充(依赖注入)
3. Aware 接口回调(BeanNameAware、ApplicationContextAware 等)
4. BeanPostProcessor#postProcessBeforeInitialization
5. @PostConstruct / InitializingBean
6. BeanPostProcessor#postProcessAfterInitialization
7. Bean 就绪,可使用
8. @PreDestroy / DisposableBean → 销毁

19. @Transactional 失效场景

  • 方法不是 public
  • 同类内部调用(this.xxx())绕过代理
  • 异常被 try-catch 吃掉
  • 抛出的不是 RuntimeException(默认只在 RuntimeException 回滚)
  • Bean 没被 Spring 管理

20. Spring MVC 流程

请求 → DispatcherServlet → HandlerMapping(找 Controller)
→ HandlerAdapter(调用方法)→ 返回 ModelAndView / @ResponseBody
→ ViewResolver(解析视图)→ 响应

21. Spring Boot 自动配置

@SpringBootApplication → @EnableAutoConfiguration
→ 加载 META-INF/spring.factories 中的 AutoConfiguration 类
→ 按 @Conditional 条件判断(有对应类才生效)

四、JVM

22. JVM 内存结构

线程私有:程序计数器、虚拟机栈、本地方法栈
线程共享:堆、方法区(元空间)

23. GC 算法

算法逻辑适用
标记-清除标记存活→清除死亡老年代(有碎片)
复制分成两半,存活移到另一半新生代
标记-整理标记存活→向一端移动老年代(无碎片)

分代回收思路:

  • 新生代:复制算法(存活率低,效率高)
  • 老年代:标记-清除 / 标记-整理(存活率高)

24. 类加载机制

加载 → 链接(验证→准备→解析)→ 初始化 → 使用 → 卸载

双亲委派:

加载一个类时,先交给父 ClassLoader
父找不到才自己加载
目的:防止核心 API 被替换(如自己写 java.lang.String)