当前位置: 首页 > news >正文

2026最全 Java 面试题精选(附答案):Spring全家桶高频考点整理


本文是 Java 系列教程,从基础到进阶,附完整代码示例,收藏备用!


一、前言

Java 作为企业级开发的主流语言,面试考察点覆盖面广、深度大。本文整理了 2026 年最新高频面试题,涵盖 Java 基础、集合、并发、JVM、Spring 全家桶等核心知识点,每道题都附带详细答案和代码示例。

适合人群:

  • 准备 Java 后端面试的开发者
  • 需要系统复习 Java 知识点的工程师
  • 想了解最新面试趋势的技术人员

二、Java 基础篇

2.1 HashMap 底层原理

问题:讲讲 HashMap 的底层实现?JDK 1.8 做了哪些优化?

答案:

HashMap 基于数组 + 链表 + 红黑树实现:

// 核心数据结构 transient Node<K,V>[] table; // 哈希桶数组 transient int size; // 元素数量 int threshold; // 扩容阈值 = 容量 * 负载因子 final float loadFactor; // 默认 0.75 // 链表节点 static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; // 指向下一个节点 }

JDK 1.8 优化:

  1. 链表转红黑树:当链表长度 ≥ 8 且数组长度 ≥ 64 时,链表转为红黑树,查询复杂度从 O(n) 降到 O(log n)
  2. 尾插法:插入时使用尾插法替代头插法,避免并发扩容时的死循环
  3. 扩容优化:扩容时不需要重新计算 hash,只需判断 hash 新增的高位是 0 还是 1
// 扩容时的 rehash 优化 final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; // 容量翻倍 int newCap = oldCap << 1; // 迁移数据时,只需看 hash 新增的高位 // (e.hash & oldCap) == 0 留在原位置,否则移到原位置 + oldCap }

2.2 ConcurrentHashMap 线程安全实现

问题:ConcurrentHashMap 如何保证线程安全?1.7 和 1.8 有什么区别?

答案:

JDK 1.7:分段锁(Segment)

// 1.7 结构:Segment[] + HashEntry[] final Segment<K,V>[] segments; static final class Segment<K,V> extends ReentrantLock { transient volatile HashEntry<K,V>[] table; // 每个 Segment 独立加锁 }

JDK 1.8:CAS + synchronized

// 1.8 结构:Node[] + 链表/红黑树 // 锁粒度细化到每个桶(链表头节点) final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); int hash = spread(key.hashCode()); int binCount = 0; for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; // 1. 数组未初始化,CAS 初始化 if (tab == null || (n = tab.length) == 0) tab = initTable(); // 2. 目标桶为空,CAS 插入 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) break; } // 3. 正在扩容,协助扩容 else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); // 4. 桶非空,synchronized 锁定头节点 else { synchronized (f) { if (tabAt(tab, i) == f) { // 链表操作或树操作 } } } } }

1.8 优势:

  • 锁粒度更细(桶级别 vs Segment 级别)
  • 使用 CAS + synchronized 替代 ReentrantLock,性能更好
  • 支持扩容时并发协助迁移

2.3 volatile 关键字

问题:volatile 的作用是什么?如何保证可见性和有序性?

答案:

public class VolatileDemo { // volatile 保证可见性和禁止指令重排序 private volatile boolean flag = false; public void writer() { flag = true; // 写 volatile 变量 } public void reader() { while (!flag) { // 等待 } System.out.println("看到了 flag 的变化"); } }

实现原理:

  1. 可见性:写 volatile 变量会立即刷新到主内存,读 volatile 变量会从主内存刷新
  2. 有序性:插入内存屏障(Memory Barrier)禁止指令重排序

内存屏障:

  • StoreStore 屏障:禁止普通写与 volatile 写重排序
  • StoreLoad 屏障:禁止 volatile 写与后续 volatile 读/写重排序
  • LoadLoad 屏障:禁止 volatile 读与普通读重排序
  • LoadStore 屏障:禁止 volatile 读与普通写重排序

三、Java 并发篇

3.1 synchronized 锁升级过程

问题:synchronized 的锁升级过程是怎样的?

答案:

synchronized 锁有 4 种状态,只能升级不能降级:

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

1. 偏向锁(Biased Locking)

// 场景:只有一个线程访问同步块 // 原理:在对象头 Mark Word 中记录线程 ID,下次同一线程访问无需 CAS // 开启偏向锁(默认开启) -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0

2. 轻量级锁(Lightweight Locking)

// 场景:多个线程交替访问(无竞争) // 原理:CAS 自旋尝试获取锁,避免线程阻塞 // 自旋次数默认 10 次,可通过参数调整 -XX:PreBlockSpin=10

3. 重量级锁(Heavyweight Locking)

// 场景:多个线程同时竞争 // 原理:线程阻塞,等待操作系统调度

对象头 Mark Word 结构:

| 锁状态 | 存储内容 | |---------|-------------------------------------| | 无锁 | 对象哈希码 + 分代年龄 + 0 01 | | 偏向锁 | 线程 ID + Epoch + 分代年龄 + 1 01 | | 轻量级锁 | 指向栈中锁记录的指针 00 | | 重量级锁 | 指向互斥量(Monitor)的指针 10 | | GC 标记 | 空 11 |

3.2 AQS 原理

问题:AbstractQueuedSynchronizer(AQS)的原理是什么?

答案:

AQS 是 JUC 包的核心框架,ReentrantLock、CountDownLatch、Semaphore 都基于它实现。

核心结构:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer { // 同步状态,volatile 保证可见性 private volatile int state; // 等待队列头节点 private transient volatile Node head; // 等待队列尾节点 private transient volatile Node tail; // 独占线程 private transient Thread exclusiveOwnerThread; } // 队列节点 static final class Node { volatile int waitStatus; // 节点状态 volatile Node prev; // 前驱节点 volatile Node next; // 后继节点 volatile Thread thread; // 绑定的线程 }

获取锁流程:

// ReentrantLock 的 lock 方法 final void lock() { // 1. 尝试 CAS 获取锁 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); // 获取失败,进入队列 } // AQS 的 acquire 方法 public final void acquire(int arg) { if (!tryAcquire(arg) && // 子类实现 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }

3.3 线程池参数与拒绝策略

问题:线程池的核心参数有哪些?拒绝策略有哪些?

答案:

public ThreadPoolExecutor( int corePoolSize, // 核心线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 非核心线程存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 任务队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略 )

任务执行流程:

  1. 当前运行线程 < corePoolSize:创建新线程执行任务
  2. 当前运行线程 ≥ corePoolSize:任务进入队列
  3. 队列已满且线程 < maximumPoolSize:创建非核心线程
  4. 队列已满且线程 ≥ maximumPoolSize:执行拒绝策略

拒绝策略:

// 1. AbortPolicy(默认):直接抛出异常 new ThreadPoolExecutor.AbortPolicy(); // 2. CallerRunsPolicy:由调用线程执行任务 new ThreadPoolExecutor.CallerRunsPolicy(); // 3. DiscardPolicy:静默丢弃任务 new ThreadPoolExecutor.DiscardPolicy(); // 4. DiscardOldestPolicy:丢弃队列最老的任务 new ThreadPoolExecutor.DiscardOldestPolicy(); // 5. 自定义拒绝策略 new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { // 记录日志、持久化到数据库等 log.error("Task rejected: {}", r); } };

线程池最佳实践:

// CPU 密集型:核心线程数 = CPU 核心数 + 1 int cpuCores = Runtime.getRuntime().availableProcessors(); ExecutorService cpuPool = new ThreadPoolExecutor( cpuCores + 1, cpuCores + 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(100) ); // IO 密集型:核心线程数 = CPU 核心数 * 2 ExecutorService ioPool = new ThreadPoolExecutor( cpuCores * 2, cpuCores * 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000) );

四、JVM 篇

4.1 JVM 内存模型

问题:讲讲 JVM 内存结构和垃圾回收机制?

答案:

JVM 内存结构:

┌─────────────────────────────────────┐ │ 堆(Heap) │ │ ├─ 年轻代(Young Generation) │ │ │ ├─ Eden 区(8/10) │ │ │ ├─ Survivor0(1/10) │ │ │ └─ Survivor1(1/10) │ │ └─ 老年代(Old Generation) │ ├─────────────────────────────────────┤ │ 元空间(Metaspace)JDK 8+ │ │ (之前是永久代 PermGen) │ ├─────────────────────────────────────┤ │ 虚拟机栈(VM Stack) │ │ (每个线程私有,栈帧存储局部变量) │ ├─────────────────────────────────────┤ │ 本地方法栈(Native Method Stack) │ ├─────────────────────────────────────┤ │ 程序计数器(PC Register) │ ├─────────────────────────────────────┤ │ 直接内存(Direct Memory) │ │ (NIO 使用,不受 JVM 堆大小限制) │ └─────────────────────────────────────┘

垃圾回收算法:

// 1. 标记-清除(Mark-Sweep) // 优点:简单 // 缺点:产生内存碎片 // 2. 复制算法(Copying) // 年轻代使用,Eden → Survivor 的复制 // 优点:无碎片 // 缺点:内存利用率 50% // 3. 标记-整理(Mark-Compact) // 老年代使用 // 优点:无碎片 // 缺点:需要移动对象,STW 时间较长

G1 垃圾收集器:

# G1 将堆划分为多个 Region(1MB~32MB) # 优先回收垃圾最多的 Region # 启用 G1 -XX:+UseG1GC # 设置目标最大停顿时间(默认 200ms) -XX:MaxGCPauseMillis=200 # 设置 Region 大小 -XX:G1HeapRegionSize=16m

4.2 类加载机制

问题:类的加载过程是怎样的?双亲委派模型是什么?

答案:

类加载过程:

加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
// 加载:读取 .class 文件,生成 Class 对象 Class<?> clazz = Class.forName("com.example.User"); // 验证:文件格式、元数据、字节码、符号引用验证 // 准备:为类变量分配内存并设置默认值 // static int a = 123; // 准备阶段 a = 0,初始化阶段 a = 123 // 解析:符号引用转直接引用 // 初始化:执行 <clinit>() 方法(类构造器)

双亲委派模型:

┌─────────────────┐ │ Bootstrap │ ← 加载 %JAVA_HOME%/lib 下的类 │ ClassLoader │ (rt.jar 等核心类库) └────────┬────────┘ │ 委派 ┌────────▼────────┐ │ Extension │ ← 加载 %JAVA_HOME%/lib/ext 下的类 │ ClassLoader │ └────────┬────────┘ │ 委派 ┌────────▼────────┐ │ Application │ ← 加载 classpath 下的类 │ ClassLoader │ (用户自定义类) └────────┬────────┘ │ 委派 ┌────────▼────────┐ │ Custom │ ← 用户自定义 ClassLoader │ ClassLoader │ └─────────────────┘

打破双亲委派:

// Tomcat 为每个 Web 应用创建独立的 ClassLoader // 实现应用间类隔离 public class WebAppClassLoader extends URLClassLoader { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { // 1. 先在本地缓存查找 // 2. 本地未找到,自己加载(不先委派给父类) // 3. 自己加载不到,再委派给父类 } }

五、Spring 篇

5.1 Spring IoC 容器启动流程

问题:Spring IoC 容器的启动流程是怎样的?

答案:

// 1. 创建 ApplicationContext AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 核心启动流程(refresh() 方法) public void refresh() { // 1. 准备上下文环境 prepareRefresh(); // 2. 获取 BeanFactory(DefaultListableBeanFactory) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3. 准备 BeanFactory prepareBeanFactory(beanFactory); // 4. 子类扩展(如注册 ServletContextAwareProcessor) postProcessBeanFactory(beanFactory); // 5. 执行 BeanFactoryPostProcessor invokeBeanFactoryPostProcessors(beanFactory); // 6. 注册 BeanPostProcessor registerBeanPostProcessors(beanFactory); // 7. 初始化 MessageSource initMessageSource(); // 8. 初始化事件广播器 initApplicationEventMulticaster(); // 9. 子类扩展(如创建 Tomcat 服务器) onRefresh(); // 10. 注册监听器 registerListeners(); // 11. 实例化所有非懒加载的单例 Bean finishBeanFactoryInitialization(beanFactory); // 12. 完成刷新 finishRefresh(); }

5.2 Spring Bean 生命周期

问题:Spring Bean 的生命周期是怎样的?

答案:

@Component public class UserService implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean { // 1. 实例化(构造函数) public UserService() { System.out.println("1. 构造方法"); } // 2. 属性赋值(依赖注入) @Autowired private UserDao userDao; // 3. 设置 BeanName @Override public void setBeanName(String name) { System.out.println("2. BeanNameAware.setBeanName: " + name); } // 4. 设置 ApplicationContext @Override public void setApplicationContext(ApplicationContext ctx) { System.out.println("3. ApplicationContextAware.setApplicationContext"); } // 5. @PostConstruct 方法 @PostConstruct public void postConstruct() { System.out.println("4. @PostConstruct"); } // 6. InitializingBean.afterPropertiesSet @Override public void afterPropertiesSet() { System.out.println("5. InitializingBean.afterPropertiesSet"); } // 7. 自定义 init-method public void customInit() { System.out.println("6. custom init-method"); } // 销毁阶段 @PreDestroy public void preDestroy() { System.out.println("7. @PreDestroy"); } @Override public void destroy() { System.out.println("8. DisposableBean.destroy"); } }

BeanPostProcessor 扩展点:

@Component public class CustomBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { // 初始化之前处理(如 @PostConstruct 之前) System.out.println("BeforeInitialization: " + beanName); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { // 初始化之后处理(如 AOP 代理在此创建) System.out.println("AfterInitialization: " + beanName); return bean; } }

5.3 Spring 事务传播行为

问题:Spring 事务的传播行为有哪些?

答案:

@Service public class OrderService { @Autowired private PaymentService paymentService; // REQUIRED(默认):当前有事务就加入,没有就新建 @Transactional(propagation = Propagation.REQUIRED) public void createOrder() { // 业务逻辑 paymentService.pay(); // 加入当前事务 } // REQUIRES_NEW:挂起当前事务,新建独立事务 @Transactional(propagation = Propagation.REQUIRES_NEW) public void logOperation() { // 独立事务,不受外部事务回滚影响 } // NESTED:在当前事务中创建保存点,可独立回滚 @Transactional(propagation = Propagation.NESTED) public void updateInventory() { // 失败只回滚到保存点,外部事务继续 } // SUPPORTS:有事务就加入,没有就以非事务执行 @Transactional(propagation = Propagation.SUPPORTS) public void queryData() { // 查询操作不需要事务 } // MANDATORY:必须在事务中执行,否则抛异常 @Transactional(propagation = Propagation.MANDATORY) public void mandatoryOperation() { // 强制要求有事务 } // NOT_SUPPORTED:挂起当前事务,以非事务执行 @Transactional(propagation = Propagation.NOT_SUPPORTED) public void sendNotification() { // 发送通知不需要事务 } // NEVER:必须在非事务中执行,否则抛异常 @Transactional(propagation = Propagation.NEVER) public void neverInTransaction() { // 禁止在事务中执行 } }

事务失效场景:

@Service public class UserService { // ❌ 失效:同类方法调用,@Transactional 不生效 public void outer() { inner(); // 实际是 this.inner(),不经过代理 } @Transactional public void inner() { // 事务不生效 } // ✅ 解决:注入自身代理对象 @Autowired private UserService self; public void outer() { self.inner(); // 通过代理调用 } }

六、Spring Boot 篇

6.1 自动装配原理

问题:Spring Boot 自动装配的原理是什么?

答案:

// @SpringBootApplication = // @Configuration + @EnableAutoConfiguration + @ComponentScan @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } // @EnableAutoConfiguration 导入 AutoConfigurationImportSelector @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }

自动装配流程:

// 1. 读取 META-INF/spring.factories // key: org.springframework.boot.autoconfigure.EnableAutoConfiguration // 2. 过滤条件(@Conditional) @ConditionalOnClass(DataSource.class) // 类路径有 DataSource @ConditionalOnMissingBean(DataSource.class) // 容器中没有 DataSource Bean @ConditionalOnProperty(prefix = "spring.datasource", name = "url") // 配置存在 public class DataSourceAutoConfiguration { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } }

自定义 Starter:

// 1. 创建自动配置类 @Configuration @ConditionalOnClass(MyService.class) @EnableConfigurationProperties(MyProperties.class) public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService(MyProperties properties) { return new MyService(properties); } } // 2. 创建 META-INF/spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.MyAutoConfiguration // 3. 使用方引入依赖即可自动装配

七、总结

本文涵盖了 Java 面试的核心知识点:

模块重点内容
Java 基础HashMap、ConcurrentHashMap、volatile
并发编程synchronized 锁升级、AQS、线程池
JVM内存模型、GC 算法、类加载机制
SpringIoC 启动流程、Bean 生命周期、事务传播
Spring Boot自动装配原理

面试建议:

  1. 理解原理比背答案更重要
  2. 结合实际项目经验回答问题
  3. 多画图帮助表达(类加载、锁升级、Bean 生命周期等)

💬觉得有用的话,点个赞+收藏,关注我,每周持续更新实战教程!

标签:java | 面试 | spring | jvm | 并发编程 | 后端

http://www.jsqmd.com/news/565649/

相关文章:

  • Allegro PCB设计必备:3分钟搞定带钻孔数据的DXF文件导出(附常见错误排查)
  • 2026年杜兰小麦粉怎么选?资深面制品工厂教你3招避开采购坑 - 速递信息
  • DINO注意力可视化实战指南:3步掌握视觉Transformer内部机制
  • GodotPckTool 终极指南:轻松管理 Godot 游戏资源包的完整教程
  • ngx_http_create_locations_list
  • 佛山哪里能找到不会出现水纹烂斑的隔热条厂家 - 工业品牌热点
  • 用QMK固件打造你的专属宏键盘:从配置到实战案例
  • 2026年杜兰小麦粉排行:国产VS进口,谁更适合你的生产线? - 速递信息
  • Sonobuoy高级用例:工作负载调试与性能分析实战
  • 2026年铝镁锰板厂家排名,常州泰州靠谱的铝镁锰板制造商大盘点 - mypinpai
  • 洛谷 P2014:[CTSC1997] 选课 ← 有依赖的背包问题
  • PP-DocLayoutV3与.NET生态集成:开发C#桌面端文档处理工具
  • 旧Mac升级与macOS支持完全指南:开源系统优化工具实现老旧Mac焕新
  • Ubuntu系统资源监控实战:从命令行到图形化工具全解析
  • 2026年北京旅游服务公司Top10,含体育旅游活动的公司推荐 - mypinpai
  • 沈北汽车贴膜好去处:2026年口碑之选,汽车车衣/改色膜/汽车贴膜/隐形车衣/沈北车衣/车衣改色,汽车贴膜品牌联系方式 - 品牌推荐师
  • 如何用TradingAgents-CN构建AI驱动的智能投顾系统?从多智能体协作到实战交易决策
  • 深圳鉴定费用全景解析:高端腕表真伪鉴别、价值评估的成本逻辑与行业实践 - 时光修表匠
  • 阶段一AI基础认知
  • 如何在AMD 780M APU上实现2-3倍AI性能提升?ROCmLibs优化库完全指南
  • 集团企业发票管理难?一招实现全流程集中管控
  • 大家公认的好用卫生巾品牌有哪些?2026口碑实测:奈丝公主凭细节设计圈粉 - 华Sir1
  • 高效智能转换方案:B站缓存视频一键处理实战指南
  • 2026年 包装袋厂家推荐排行榜:医药医疗包装袋、异形袋、真空袋、吸嘴袋等塑料包装袋源头企业实力解析与选购指南 - 品牌企业推荐师(官方)
  • P14464 海底列車(collapse)
  • 2026年市场口碑好的小龙虾筛选设备厂家推荐,小龙虾分选机/小龙虾筛选机/小龙虾筛选设备,小龙虾筛选设备供应商哪个好 - 品牌推荐师
  • 超越U-Net:拆解Cellpose如何用‘图像风格’和残差块实现通用分割
  • 模拟面试回答第十七问:垃圾判定算法
  • 2026商务全自动咖啡机选购指南:高效省心选机攻略 - 品牌2026
  • 3步掌握AI模型训练:让新手也能玩转个性化Stable Diffusion模型