2026Java面试30题精解

Java面试高频30题及核心解答(2026版)

Java作为企业级开发的核心语言,其知识体系庞大。为了帮助大家高效备战2026年面试,本文将系统梳理30道高频面试题,涵盖从基础到高级的核心知识点,并提供深入解析和代码示例。

第一部分:Java基础与集合框架

1. Java的三大特性是什么?

  • 封装 :将数据(属性)和操作数据的方法(行为)捆绑在一起,对外隐藏实现细节,仅通过公共接口访问。例如,一个Student类的age属性通过setAge()方法进行校验和设置。
  • 继承 :允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码复用和层次关系。例如,Dog extends Animal
  • 多态 :同一操作作用于不同的对象,可以有不同的解释和执行结果。主要通过方法重写(Override)接口实现 实现。例如,Animal a = new Dog(); a.sound(); 调用的是Dog类的sound方法。

2. == 与 equals() 的区别?

操作符/方法 作用 示例与说明
== 1. 比较基本数据类型的 是否相等。 2. 比较引用类型的内存地址是否相同。 int a=1, b=1; a==b // true new String("hi") == new String("hi") // false
equals() 比较两个对象的内容 是否相等。Object类中默认实现为==,但许多类(如String)重写了该方法。 new String("hi").equals(new String("hi")) // true 自定义类需要重写equals()hashCode()

3. String、StringBuilder、StringBuffer的区别?

可变性 线程安全 性能 适用场景
String 不可变(final char[]) 安全(不可变对象天然线程安全) 低(频繁拼接会产生大量中间对象) 字符串常量、键值对。
StringBuilder 可变 不安全 单线程环境下字符串的频繁拼接、修改。
StringBuffer 可变 安全(方法使用synchronized修饰) 中(因锁开销) 多线程环境下字符串的频繁操作。

4. ArrayList 与 LinkedList 的区别?

对比维度 ArrayList LinkedList
底层结构 动态数组(Object[]) 双向链表(Node)
随机访问 O(1),支持快速索引 O(n),需要遍历
头部增删 O(n),需要移动元素 O(1)
尾部增删 平均O(1)(触发扩容时为O(n)) O(1)
内存占用 较小(仅存储数据) 较大(存储数据和前后节点引用)
适用场景 读多写少,频繁按索引访问 写多读少,频繁在头尾增删,或用作队列/栈。

5. HashMap的底层原理与扩容机制?

  • 数据结构:JDK 1.8后为"数组+链表+红黑树"。当链表长度超过8且数组长度大于64时,链表会转换为红黑树,以提升查询效率。
  • 核心参数
    • DEFAULT_INITIAL_CAPACITY:默认初始容量16。
    • DEFAULT_LOAD_FACTOR:默认负载因子0.75。
    • TREEIFY_THRESHOLD:树化阈值8。
  • put过程简述
    1. 计算key的hash值,确定数组下标。
    2. 若该位置为空,直接插入Node。
    3. 若不为空,则遍历链表/红黑树,根据key是否相等进行覆盖或新增。
    4. 判断是否需要树化。
    5. 判断是否需要扩容(size > capacity * loadFactor)。
  • 扩容机制 :创建一个新数组(大小为原2倍),重新计算所有元素的位置((e.hash & oldCap) == 0判断高位,决定元素留在原索引或移动到原索引+oldCap位置),这是一个耗时的操作。
第二部分:多线程与并发编程

6. 创建线程的四种方式?

  1. 继承Thread类 :重写run()方法。new MyThread().start();。不推荐,因为Java是单继承。
  2. 实现Runnable接口 :实现run()方法,将实例作为Thread的构造参数。new Thread(new MyRunnable()).start();推荐使用,更灵活。
  3. 实现Callable接口 :实现call()方法,可以返回结果和抛出异常。需要配合FutureTask使用。FutureTask<Integer> ft = new FutureTask<>(new MyCallable()); new Thread(ft).start(); Integer result = ft.get();
  4. 使用线程池(ExecutorService) :通过Executors工具类或ThreadPoolExecutor创建。企业级开发中最推荐的方式,可以有效管理线程资源,避免频繁创建销毁线程的开销。
java 复制代码
// 示例:使用线程池执行Callable任务 
import java.util.concurrent.*;

public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Future<Integer> future = executor.submit(() -> {
            Thread.sleep(1000);
            return 42;
        });
        System.out.println("异步任务结果: " + future.get()); // 输出: 异步任务结果: 42
        executor.shutdown();
    }
}

7. synchronized 与 ReentrantLock 的区别?

特性 synchronized (关键字) ReentrantLock (类)
实现层面 JVM级别,原生语法支持 JDK API级别,通过java.util.concurrent包实现
锁的获取 隐式获取和释放,进入同步代码块自动获得,退出时释放 显式调用lock()unlock()方法
锁的类型 非公平锁(默认) 可公平可非公平 (构造参数fair决定)
可中断性 不支持等待锁的过程中中断 支持 (lockInterruptibly())
条件队列 通过wait(), notify()/notifyAll() 支持多个条件变量 (newCondition())
尝试获取锁 不支持 支持 (tryLock())
适用场景 简单的同步场景,代码简洁 需要高级功能(如公平锁、可中断、超时、多条件)的复杂并发场景

8. 什么是死锁?如何避免?

死锁是指两个或以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉,它们都将无法推进下去。
产生条件(必须同时满足)

  • 互斥条件
  • 请求与保持条件
  • 不剥夺条件
  • 循环等待条件
    避免策略
  • 破坏请求与保持:一次性申请所有所需资源。
  • 破坏不剥夺:允许抢占资源。
  • 破坏循环等待:对资源进行线性排序,按序申请(如总是先申请锁A,再申请锁B)。这是最常用的策略。
第三部分:JVM与性能调优

9. JVM内存模型(运行时数据区)?

区域 作用 线程共享/私有 异常
程序计数器 当前线程所执行的字节码的行号指示器 线程私有
Java虚拟机栈 存储栈帧,包含局部变量表、操作数栈等 线程私有 StackOverflowError, OutOfMemoryError
本地方法栈 为Native方法服务 线程私有 同上
存放几乎所有的对象实例和数组 线程共享 OutOfMemoryError
方法区(元空间) 存储类信息、常量、静态变量、即时编译器编译后的代码等 线程共享 OutOfMemoryError

10. 常见的垃圾回收算法有哪些?

  • 标记-清除 :先标记所有需要回收的对象,再统一回收。缺点:产生内存碎片。
  • 复制算法 :将内存分为两块,每次只使用一块。垃圾回收时,将存活对象复制到另一块,然后清空当前块。优点 :简单高效,无碎片。缺点 :内存利用率只有50%。应用 :新生代的EdenSurvivor区。
  • 标记-整理 :标记过程同"标记-清除",但后续不是直接清除,而是让所有存活对象向一端移动,然后直接清理掉边界以外的内存。应用:老年代。
  • 分代收集 :现代JVM的主流算法。将堆分为新生代 (大量对象"朝生夕死",使用复制算法)和老年代(存活率高的对象,使用标记-整理算法)。
第四部分:Spring与微服务

11. Spring Bean的生命周期?

一个Spring Bean从创建到销毁会经历以下关键步骤:

  1. 实例化(Instantiate):通过构造器或工厂方法创建Bean实例。
  2. 属性赋值(Populate) :为Bean的属性注入值(依赖注入,@Autowired)。
  3. 初始化(Initialize)
    • 执行BeanNameAwareBeanFactoryAwareAware接口方法。
    • 执行BeanPostProcessorpostProcessBeforeInitialization方法。
    • 执行@PostConstruct注解的方法或InitializingBean接口的afterPropertiesSet方法。
    • 执行BeanPostProcessorpostProcessAfterInitialization方法(AOP代理在此生成)。
  4. 使用(In Use):Bean已就绪,可以被应用程序使用。
  5. 销毁(Destroy)
    • 容器关闭时,执行@PreDestroy注解的方法或DisposableBean接口的destroy方法。

12. Spring AOP的实现原理?

Spring AOP(面向切面编程)基于动态代理实现,主要有两种方式:

  • JDK动态代理要求目标类必须实现至少一个接口 。在运行时,通过ProxyInvocationHandler创建接口的代理实例。代理类会拦截方法调用,执行增强逻辑(通知)。
  • CGLIB动态代理 :通过生成目标类的子类 来创建代理。适用于没有实现接口的类 。它通过MethodInterceptor接口拦截方法调用。
    Spring默认策略是:如果目标对象实现了接口,则使用JDK动态代理;否则使用CGLIB。

13. Spring事务失效的常见场景?

  • 方法非public@Transactional注解只能用于public方法。
  • 方法自调用 :同一个类中,A方法(无事务)调用B方法(有@Transactional),事务不会生效。因为代理对象调用才生效,自调用是this.B(),绕过了代理。
  • 异常被捕获 :默认只在抛出RuntimeExceptionError时回滚。若异常被catch且未重新抛出,事务不会回滚。
  • 数据库引擎不支持:如MySQL的MyISAM引擎不支持事务。
  • 传播行为设置不当 :例如,在已有事务的方法中调用PROPAGATION_NOT_SUPPORTED的方法。
第五部分:数据库与缓存

14. MySQL索引失效的常见场景?

  • 违反最左前缀原则 :对于联合索引(a, b, c),查询条件WHERE b=1 AND c=2无法使用该索引。
  • 在索引列上做计算、函数或类型转换WHERE YEAR(create_time)=2024WHERE age + 10 > 30
  • 使用!=<>WHERE status != 1
  • 使用OR连接非索引列WHERE a=1 OR b=2,如果b无索引,则整个查询可能全表扫描。
  • 使用LIKE以通配符开头WHERE name LIKE '%张'
  • 字符串查询未加引号 (类型隐式转换):WHERE id = '123',若id是数字类型,传入字符串会导致索引失效。

15. Redis的持久化方式?

方式 原理 优点 缺点
RDB (快照) 定时fork子进程,将内存数据全量写入二进制dump文件(.rdb)。 1. 文件紧凑,恢复速度快。 2. 对性能影响小(fork子进程)。 1. 可能丢失最后一次快照后的数据 。 2. 数据量大时,fork过程可能阻塞。
AOF (日志) 记录每一条写命令(appendonly.aof),重启时重新执行命令恢复数据。 1. 数据安全性高 ,默认每秒同步一次。 2. AOF文件易于理解和解析。 1. 文件体积通常比RDB大。 2. 恢复速度慢。 3. 写负载高时对性能有影响。
混合持久化 RDB + AOF。先做一次RDB快照,之后的时间用AOF记录增量命令。 结合两者优点,恢复速度快且数据丢失少。 需要Redis 4.0+版本支持。
第六部分:分布式与系统设计

16. CAP理论是什么?如何理解?

CAP理论指出,一个分布式系统无法同时满足以下三个特性:

  • C (一致性 Consistency):所有节点在同一时间看到的数据完全相同。
  • A (可用性 Availability):每个请求都能得到非错的响应,但不保证数据是最新的。
  • P (分区容错性 Partition tolerance) :系统在遇到网络分区故障时,仍然能够对外提供服务。
    核心结论 :在分布式系统中,P(分区容错性)是必须接受的 ,因为网络故障无法避免。因此,实际设计是在**C(一致性)A(可用性)**之间做权衡。
  • CP系统:如ZooKeeper、HBase。保证强一致,但在网络分区时可能拒绝服务。
  • AP系统:如Eureka、Cassandra。保证高可用,但数据可能短暂不一致(最终一致)。

17. 如何设计一个短链接生成系统?

这是一个典型的高并发场景题。核心思路如下:

  1. 功能需求 :将长URL映射为短Key(如 t.cn/abc123),访问短链时重定向到原URL。
  2. 核心设计
    • 短码生成
      • 哈希算法:对长URL取MD5或MurmurHash,再转Base62编码(0-9, a-z, A-Z)取前N位。需处理哈希冲突。
      • 发号器:使用分布式ID生成器(如Snowflake算法)生成唯一ID,再将ID转为Base62短码。这是更常用的方案。
    • 映射存储 :使用短码 -> 原URL的键值对存储。由于读多写少且要求高QPS,首选Redis(内存数据库,性能极高)。
    • 跳转流程:用户访问短链 -> 服务端从Redis查询原URL -> 返回302重定向响应。
  3. 高可用与扩展
    • 使用Nginx做负载均衡。
    • Redis采用集群模式,并设置合理的过期策略。
    • 发号器服务需要保证高可用(多实例、主从)。
  4. 安全性:可以加入黑名单、防刷限流、短码混淆等机制。

以上30道题目及其深度解析,覆盖了Java技术栈的核心面试考点。理解原理、结合实际场景思考、并动手实践代码,是应对面试的关键。


参考来源

相关推荐
SHoM SSER2 小时前
Spring Boot性能提升的核武器,速度提升500%!
java·spring boot·后端
Bert.Cai2 小时前
pymysql自动提交设置
开发语言·python
weixin_425023002 小时前
Spring Boot 2.7 + JDK8 集成 Knife4j 4.1.0 教程(仅展示带注解接口)
java·spring boot·后端
追风林2 小时前
arthas 插件 使用中文
java
rleS IONS2 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
AI浩2 小时前
别卷 Prompt 了,2026 年 AI 工程的新战场是 Harness
java·人工智能·prompt
IT从业者张某某2 小时前
Dockerfile详解
java·开发语言
小白学大数据2 小时前
攻克滑动拼图反爬:Python 高效爬取网页图片实战案例
开发语言·爬虫·python
笨笨没好名字2 小时前
结构工程/机械工程/工业设计/硬件工程师面试题目(题源大疆:12+28)
人工智能·面试·职场和发展