2026 Java后端面试题总结(持续更新):Spring、MyBatis、Redis、MySQL、多线程 1. 和equals的区别面试版 比较引用是否相同equals 比较内容是否相等真正理解版 比较是不是同一个对象equals 比较这个类定义的“相等规则”2. 说一下HashMap的底层原理数组找到大概位置↓链表解决多个数据撞到同一个位置↓红黑树解决链表太长导致查询慢3. 说一下ArrayList和LinkedList的区别数组擅长找位置链表擅长改连接。ArrayList 底层基于动态数组实现查询通过下标直接定位时间复杂度 O(1)但是中间插入删除需要移动元素效率较低。LinkedList 底层基于双向链表实现插入删除只需要修改指针效率较高但是查询需要遍历时间复杂度 O(n)。另外 LinkedList 每个节点需要保存前后指针所以占用内存更多。实际开发中查询和遍历较多一般选择 ArrayList。4. 怎么搭建一个springboot项目还有你们用的springboot的版本是什么我们项目一般通过 Spring Initializr 创建 Spring Boot 项目选择 Maven 管理依赖引入 Spring Web、MyBatis、数据库驱动等依赖。项目启动类使用 SpringBootApplication 注解通过 SpringApplication.run 启动 Spring 容器。配置文件使用 application.yml 管理端口、数据库等配置。我们项目目前使用 Spring Boot 2.7.x或者3.x根据实际情况配合 JDK 8/17主要使用 Spring MVC、MyBatis、MySQL 等技术。5. RestController和Controller的区别Controller 是 Spring MVC 中用于处理页面请求的控制器方法返回值默认会被视图解析器解析成页面。RestController 是 Spring 4 提供的注解本质上等于 Controller 加 ResponseBody返回值会直接写入 HTTP 响应通常返回 JSON 数据用于开发 RESTful 接口6. 什么是IOC什么是DIIOC控制反转是指把对象的创建和管理交给 Spring 容器而不是由代码主动创建。DI依赖注入是 IOC 的具体实现方式Spring 容器创建 Bean 后通过构造方法、Setter 或字段方式把对象依赖注入到需要它的类中。简单来说IOC 解决对象由谁创建DI 解决对象如何传递。7. Autowired和Resource的区别Autowired 是 Spring 提供的注解默认按照类型进行依赖注入如果存在多个相同类型的 Bean需要配合 Qualifier 指定 Bean 名称。Resource 是 Java 提供的注解默认按照名称注入如果名称找不到再按照类型匹配。实际 Spring Boot 开发中两者都可以使用现在更推荐使用构造方法注入。8. get请求和post请求的区别GET主要用于获取资源POST主要用于提交数据。ET 和 POST 都是 HTTP 请求方法。GET 主要用于获取资源请求参数通常放在 URL 中具有幂等性适合查询。POST 主要用于提交数据请求参数通常放在请求体中常用于新增、修改操作。两者安全性主要取决于 HTTPS而不是 GET 或 POST 本身。9. 你说一下过滤器和拦截器的区别过滤器Filter是 Servlet 层面的拦截器Interceptor是 Spring MVC 层面的。Filter 和 Interceptor 都可以实现请求拦截但是作用层级不同。Filter 属于 Servlet 规范在请求进入 Spring MVC 之前执行能处理所有请求但是不知道具体 Controller 信息。Interceptor 属于 Spring MVC在 DispatcherServlet 之后、Controller 执行之前执行可以获取 Handler 信息更适合做登录认证和权限控制。执行顺序上 Filter 比 Interceptor 更早。10. 你们公司是怎么管理分支的遇到代码冲突怎么解决们项目一般采用 Git 分支管理比如 master/main 作为生产分支develop 作为开发分支每个需求创建独立 feature 分支。开发完成后提交 Merge Request由其他成员 Code Review 后合并。遇到代码冲突时首先通过 git status 查看冲突文件然后手动比较双方修改根据业务保留或合并代码解决后 git add 和 git commit 完成合并。平时通过及时拉取最新代码、小功能提交来减少冲突。11. 你们是怎么保存用户登录信息的你们的jwt需要在服务端存储吗说一下jwt的组成部分有哪些如何防篡改我们用户登录成功后服务端生成 JWT Token 返回客户端客户端保存 Token后续请求通过 Authorization Header 携带 Token。JWT 本身是无状态认证正常情况下服务端不需要保存 Token服务端通过签名校验 Token 是否被篡改。JWT 由 Header、Payload、Signature 三部分组成Header 保存算法信息Payload 保存用户信息和过期时间Signature 用密钥对前两部分签名防止数据被修改。如果需要实现主动注销、踢下线等功能可以在 Redis 中保存 Token 黑名单或者维护 Token 状态。12. 你们项目是怎么处理异常的你说一下怎么实现全局自定义异常处理器我们项目使用 Spring Boot 的全局异常处理机制统一处理异常通过 RestControllerAdvice 创建全局异常处理类通过 ExceptionHandler 捕获不同类型异常。业务异常会自定义 BusinessException在 Service 层发现业务问题时主动抛出由全局处理器转换成统一响应格式返回给前端。同时会区分业务异常、参数校验异常和系统异常避免 Controller 中大量 try-catch提高代码可维护性。13. 内连接和外连接有什么区别内连接 INNER JOIN 是返回两个表中满足连接条件的数据只返回匹配成功的记录。外连接分为左外连接和右外连接左连接保留左表全部数据右表没有匹配时显示 NULL右连接反之。实际开发中左连接使用比较多例如查询所有用户以及用户对应的数据即使用户没有相关记录也需要展示。LEFT JOIN 后面 WHERE 条件写错会变成 INNER JOIN。14. char和varchar的区别CHAR 和 VARCHAR 都是 MySQL 中存储字符串的数据类型。CHAR 是固定长度类型创建时指定长度存储不足会使用空格填充适合存储长度固定的数据例如手机号、身份证号。VARCHAR 是可变长度类型只保存实际数据长度节省空间适合用户名、地址等长度不固定的数据。实际开发中 VARCHAR 使用更多。15. 什么是事务你说一下事务有哪些特性事务是一组数据库操作的集合这些操作要么全部成功要么全部失败通过事务可以保证数据的一致性。事务具有 ACID 四个特性原子性表示事务不可分割要么成功要么失败一致性表示事务执行前后数据保持正确状态隔离性表示多个事务并发执行时互不影响持久性表示事务提交后的数据会永久保存。16. mybatis的#和$的区别#{} 是预编译参数占位符替换安全${} 是字符串直接拼接有 SQL 注入风险MyBatis 中 #{} 和KaTeX parse error: Expected EOF, got # at position 21: …以传递参数但是实现方式不同。#̲{} 使用预编译方式通过 P…{} 是直接字符串替换会把参数拼接到 SQL 中存在 SQL 注入风险一般只用于动态表名、字段名等场景并且需要严格校验参数来源。17. mybatis的接口方法支持重载吗为什么MyBatis 的 Mapper 接口方法不支持重载。MyBatis 的 Mapper 接口方法不支持重载。虽然 Java 方法支持重载但是 MyBatis 是通过 Mapper 的 namespace 加方法名 id 来绑定 SQL 的并不会根据参数列表区分方法。如果出现同名方法会导致 SQL 映射冲突。因此 Mapper 接口中的方法名必须唯一。18. 你在项目中有使用过多线程吗项目中使用过多线程主要用于处理一些耗时任务例如文件上传、图片处理、异步通知等避免阻塞主业务流程。在 Spring Boot 中通常使用线程池或者 Async 实现异步处理而不是直接创建 Thread。使用多线程时需要注意线程安全问题比如多个线程同时修改共享变量可能导致数据不一致可以通过 synchronized、Lock 或线程安全集合等方式解决。19. 线程池的作用是什么线程池的作用是管理线程减少线程创建和销毁的开销提高系统性能并控制并发数量。线程池主要用于管理线程避免频繁创建和销毁线程带来的性能开销。它可以复用线程提高系统响应速度同时通过限制线程数量控制并发避免大量线程导致系统资源耗尽。在项目中通常使用 ThreadPoolExecutor 或 Spring 的线程池处理异步任务例如消息发送、文件处理、数据同步等。20. 线程池有哪些核心参数线程池核心参数决定了创建多少线程、任务怎么排队、线程什么时候回收、任务满了怎么办。ThreadPoolExecutor 有 7 个核心参数corePoolSize 表示核心线程数maximumPoolSize 表示最大线程数keepAliveTime 表示非核心线程空闲存活时间TimeUnit 是时间单位workQueue 是任务等待队列ThreadFactory 用于创建线程RejectedExecutionHandler 是任务达到最大容量后的拒绝策略。线程池通过这些参数控制线程创建、任务排队和资源释放。21. redis为什么这么快Redis 快的主要原因基于内存存储 单线程事件模型 高效数据结构 IO多路复用。Redis 快主要有几个原因第一Redis 基于内存存储避免了磁盘 IO第二Redis 使用高效的数据结构比如 Hash、跳表等第三Redis 使用 IO 多路复用一个线程可以处理大量客户端连接第四Redis 的核心命令执行采用单线程模型避免了线程切换和锁竞争第五Redis 操作简单数据结构针对高性能场景进行了优化。22. 说一下redis的常用数据类型及使用场景Redis 提供不同数据结构是为了适配不同业务场景。Redis 常用数据类型包括 String、Hash、List、Set、ZSet。String 常用于缓存和计数器Hash 适合存储对象List 可以实现消息队列Set 用于去重和集合运算ZSet 常用于排行榜。实际项目会根据数据特点选择不同的数据结构。23. 什么是aop说一下实现aop的步骤有哪些通知项目中哪里用到了aopAOP 是把一些与业务无关但很多地方都需要的功能例如日志、权限、事务抽取出来在不修改业务代码的情况下统一增强业务方法。AOP 是 Spring 提供的面向切面编程思想用于将日志、权限、事务等公共功能从业务代码中抽离通过动态代理方式在运行期间对目标方法进行增强。实现 AOP 主要步骤是引入 spring-boot-starter-aop 依赖创建切面类使用 Aspect 和 Component 注解定义切入点 Pointcut然后通过 Before、After、Around 等通知实现增强逻辑。项目中常用于接口日志记录、权限校验、接口耗时统计以及事务控制其中 Spring 的 Transactional 底层也是通过 AOP 实现。24. Spring中的Bean是线程安全的吗Spring Bean 默认不是线程安全的是否线程安全取决于 Bean 的作用域和 Bean 内部是否有共享状态。Spring Bean 默认是单例的但是单例 Bean 不代表线程安全。线程安全主要取决于 Bean 是否存在共享状态。如果 Bean 是无状态的例如 Service 中只处理方法参数一般是线程安全的如果 Bean 中定义了成员变量并被多个线程修改就可能出现线程安全问题。实际开发中通常通过设计无状态 Bean、使用线程安全集合、锁机制或者 ThreadLocal 来保证线程安全。25. Springboot自动配置原理Spring Boot 自动配置就是根据项目中引入的依赖和配置文件自动判断需要哪些 Bean并自动创建和配置这些 Bean减少手动配置。Spring Boot 自动配置是通过 EnableAutoConfiguration 实现的。项目启动时Spring Boot 会加载 META-INF 中定义的自动配置类然后根据条件注解例如 ConditionalOnClass、ConditionalOnMissingBean、ConditionalOnProperty判断当前环境是否满足条件如果满足就自动向 Spring 容器中注册对应的 Bean。这样开发者只需要引入对应 starter 依赖和简单配置就可以使用相关功能。26. 说下linux常见的命令有哪些Linux 常用命令主要包括文件操作、进程管理、网络排查和服务部署相关命令。比如文件操作使用 ls、cd、mkdir、cp、mv、rm查看日志使用 cat、tail -f、grep进程管理使用 ps、top、kill网络排查使用 ping、netstat、curl磁盘和资源查看使用 df、du、free部署 Spring Boot 服务时常用 java -jar、nohup、systemctl 等命令。