Java、Spring、SpringMVC、SpringBoot和Redis常见面试题
一、Java基础
1. JDK、JRE和JVM的区别是什么?
答案:
- JVM (Java Virtual Machine):Java虚拟机,负责将字节码转换为特定平台的机器码并执行。
- JRE (Java Runtime Environment):Java运行环境,包含JVM和Java核心类库。
- JDK (Java Development Kit):Java开发工具包,包含JRE和开发工具(编译器、调试器等)。
2. Java的8种基本数据类型有哪些?
答案:
- 整型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)
- 浮点型:float(4字节)、double(8字节)
- 字符型:char(2字节)
- 布尔型:boolean(1位)
3. String、StringBuffer和StringBuilder的区别?
答案:
- String:不可变字符串,每次修改都会创建新对象,线程安全。
- StringBuffer:可变字符串,支持线程安全的修改操作,使用synchronized关键字。
- StringBuilder:可变字符串,非线程安全,性能优于StringBuffer,适用于单线程环境。
4. 什么是自动装箱和拆箱?
答案:
- 自动装箱:基本数据类型自动转换为对应的包装类对象。例如:
int i = 10; Integer obj = i; - 自动拆箱:包装类对象自动转换为对应的基本数据类型。例如:
Integer obj = 10; int i = obj;
5. final关键字的作用?
答案:
- 修饰类:该类不能被继承。
- 修饰方法:该方法不能被重写。
- 修饰变量:该变量不能被重新赋值,必须初始化。
二、Java并发编程
6. 什么是线程和进程?它们的区别?
答案:
- 进程:操作系统资源分配的基本单位,每个进程有独立的内存空间。
- 线程:CPU调度的基本单位,共享进程的内存空间。
- 区别:进程间通信复杂,线程间通信简单;进程切换开销大,线程切换开销小;进程拥有独立资源,线程共享进程资源。
7. synchronized和ReentrantLock的区别?
答案:
- synchronized:Java内置关键字,自动加锁和释放锁,可重入,非公平锁。
- ReentrantLock:显式的锁对象,需要手动加锁和释放锁,可重入,支持公平锁和非公平锁。
- 优势:ReentrantLock提供了中断响应、超时获取锁、条件变量等高级功能。
8. 什么是线程池?为什么使用线程池?
答案:
- 线程池:管理一组工作线程的资源池,避免频繁创建和销毁线程的开销。
- 优势:
- 降低资源消耗:复用已有线程
- 提高响应速度:线程已创建,无需等待
- 提高线程可管理性:统一分配和监控
- 提供更多功能:定时执行、单线程执行等
9. Java中的线程池有哪些核心参数?
答案:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:非核心线程的空闲时间
- workQueue:工作队列
- threadFactory:线程工厂
- handler:拒绝策略
10. 什么是线程安全?如何实现线程安全?
答案:
- 线程安全:多线程环境下,程序能正确处理共享资源,不出现数据不一致问题。
- 实现方式:
- 同步代码块/方法(synchronized)
- 显式锁(ReentrantLock)
- 原子类(AtomicXXX)
- 线程安全的集合类(ConcurrentHashMap等)
- 线程本地存储(ThreadLocal)
三、Spring框架
11. Spring框架的核心特性有哪些?
答案:
- 控制反转(IoC):将对象的创建和管理权交给Spring容器
- 依赖注入(DI):通过构造函数、setter方法或字段注入依赖
- 面向切面编程(AOP):将横切关注点与业务逻辑分离
- 声明式事务:通过注解或XML配置管理事务
- 集成测试:提供测试支持
12. Spring中的Bean的生命周期?
答案:
- 实例化Bean(调用构造方法)
- 设置Bean属性(依赖注入)
- 调用BeanNameAware的setBeanName方法
- 调用BeanFactoryAware的setBeanFactory方法
- 调用ApplicationContextAware的setApplicationContext方法
- 调用BeanPostProcessor的postProcessBeforeInitialization方法
- 调用InitializingBean的afterPropertiesSet方法
- 调用自定义init-method
- 调用BeanPostProcessor的postProcessAfterInitialization方法
- Bean就绪,可以使用
- 容器关闭时,调用DisposableBean的destroy方法
- 调用自定义destroy-method
13. Spring中的依赖注入方式有哪些?
答案:
- 构造函数注入:通过构造方法传递依赖
- Setter方法注入:通过setter方法设置依赖
- 字段注入:直接在字段上使用@Autowired注解
- 接口注入:实现特定接口进行依赖注入(较少使用)
14. Spring中的AOP的作用是什么?主要应用场景?
答案:
- 作用:将横切关注点(如日志、事务、安全)与业务逻辑分离,提高代码复用性和可维护性。
- 应用场景:
- 事务管理
- 日志记录
- 权限控制
- 性能监控
- 异常处理
15. Spring中的事务传播行为有哪些?
答案:
- REQUIRED:如果当前没有事务,创建新事务;如果已有事务,加入该事务
- SUPPORTS:如果当前有事务,加入该事务;如果没有事务,以非事务方式执行
- MANDATORY:必须在事务中执行,否则抛出异常
- REQUIRES_NEW:创建新事务,挂起当前事务
- NOT_SUPPORTED:以非事务方式执行,挂起当前事务
- NEVER:以非事务方式执行,如果当前有事务,抛出异常
- NESTED:如果当前有事务,创建嵌套事务;如果没有事务,创建新事务
四、SpringMVC
16. SpringMVC的工作流程是什么?
答案:
- 用户发送请求到前端控制器DispatcherServlet
- DispatcherServlet根据请求URL调用HandlerMapping
- HandlerMapping返回Handler执行链
- DispatcherServlet调用HandlerAdapter
- HandlerAdapter执行Handler并返回ModelAndView
- DispatcherServlet将ModelAndView传递给ViewResolver
- ViewResolver解析并返回View
- DispatcherServlet渲染View并返回响应
17. SpringMVC中的常用注解有哪些?
答案:
- @Controller:标识控制器类
- @RestController:@Controller和@ResponseBody的组合
- @RequestMapping:映射请求URL
- @RequestParam:获取请求参数
- @PathVariable:获取URL路径参数
- @RequestBody:将请求体转换为对象
- @ResponseBody:将返回值写入响应体
- @SessionAttributes:将模型属性存储到session中
- @ModelAttribute:绑定请求参数到模型属性
18. SpringMVC中的拦截器有什么作用?如何实现?
答案:
- 作用:拦截用户请求,在请求处理前后执行特定操作。
- 实现方式:
- 实现HandlerInterceptor接口
- 重写preHandle、postHandle、afterCompletion方法
- 在Spring配置文件中注册拦截器
19. SpringMVC中的异常处理机制有哪些?
答案:
- @ExceptionHandler:在Controller中处理异常
- @ControllerAdvice:全局异常处理
- SimpleMappingExceptionResolver:XML配置的异常处理器
- ResponseStatusExceptionResolver:处理带有@ResponseStatus注解的异常
20. SpringMVC如何实现文件上传?
答案:
- 添加依赖:commons-fileupload
- 配置MultipartResolver
- 在Controller中使用@RequestParam("file") MultipartFile file接收文件
- 调用transferTo方法保存文件
五、SpringBoot
21. SpringBoot的主要特点是什么?
答案:
- 自动配置:根据类路径上的依赖自动配置应用
- 起步依赖:提供一系列starter POM简化依赖管理
- 嵌入式容器:内置Tomcat、Jetty等容器
- 无代码生成和XML配置:基于JavaConfig
- 生产就绪功能:健康检查、指标监控等
- 简化Maven配置:提供父POM管理版本依赖
22. SpringBoot的自动配置原理是什么?
答案:
- 基于@EnableAutoConfiguration注解
- 扫描classpath下的META-INF/spring.factories文件
- 根据文件中配置的自动配置类进行加载
- 通过条件注解(@ConditionalOnClass、@ConditionalOnMissingBean等)决定是否应用配置
23. SpringBoot的核心注解有哪些?
答案:
- @SpringBootApplication:组合了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan
- @SpringBootConfiguration:标识配置类
- @EnableAutoConfiguration:启用自动配置
- @ComponentScan:扫描组件
- @ConfigurationProperties:绑定配置属性
- @EnableCaching:启用缓存
- @EnableAsync:启用异步方法
24. SpringBoot和传统Spring项目的区别?
答案:
- 配置简化:减少XML配置,使用JavaConfig和注解
- 内嵌容器:无需外部容器,直接运行jar包
- 依赖管理:starter POM简化依赖配置
- 自动装配:智能配置,减少手动配置
- 开发体验:热部署、指标监控等功能
- 打包方式:可以打包为jar或war
25. SpringBoot中的配置文件有哪些格式?它们有什么区别?
答案:
- application.properties:键值对格式
- application.yml:YAML格式,层次结构更清晰
区别:
- YAML格式更易读,支持层次结构
- properties格式更通用,兼容性更好
- YAML对缩进敏感,properties不敏感
六、Redis
26. Redis的特点有哪些?
答案:
- 内存存储:高性能,读写速度快
- 持久化:支持RDB和AOF持久化
- 数据类型丰富:String、List、Set、Hash、ZSet等
- 支持事务:原子性操作
- 支持发布订阅:消息队列功能
- 支持Lua脚本:自定义原子操作
- 主从复制:高可用
- 哨兵和集群模式:高可用和横向扩展
27. Redis的数据类型有哪些?使用场景?
答案:
- String:字符串、数字、二进制数据,用于缓存、计数器、分布式锁
- List:有序列表,用于消息队列、最新消息排行
- Set:无序集合,用于去重、共同好友
- Hash:键值对集合,用于存储对象、用户信息
- ZSet:有序集合,用于排行榜、计分系统
- Bitmap:位图,用于统计、签到
- HyperLogLog:基数统计,用于独立访客统计
28. Redis的持久化机制有哪些?区别?
答案:
- RDB:快照方式,定期将内存数据保存到磁盘
- 优点:恢复速度快,文件小
- 缺点:可能丢失数据
- AOF:日志方式,记录每个写操作
- 优点:数据安全性高
- 缺点:文件大,恢复速度慢
- 混合持久化:Redis 4.0+支持,结合了两者的优点
29. Redis的缓存穿透、缓存击穿、缓存雪崩的区别和解决方案?
答案:
- 缓存穿透:查询不存在的数据,导致请求直接打到数据库
- 解决方案:缓存空对象、布隆过滤器
- 缓存击穿:热点key过期,大量请求同时访问数据库
- 解决方案:设置永不过期、互斥锁、缓存预热
- 缓存雪崩:大量key同时过期,请求全部打到数据库
- 解决方案:设置随机过期时间、分层缓存、热点数据永不过期
30. Redis的分布式锁如何实现?
答案:
-- 获取锁
SET lock_key random_value NX PX 30000
-- 释放锁(使用Lua脚本保证原子性)
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
注意事项:
- 使用随机值防止误删
- 设置过期时间避免死锁
- 释放锁使用Lua脚本保证原子性
- 考虑锁的重入性、可重试性等
31. Redis的主从复制原理是什么?
答案:
- 全量同步:从服务器连接主服务器,发送SYNC命令,主服务器生成RDB文件并发送给从服务器
- 增量同步:主服务器将写操作记录到复制缓冲区,同步给从服务器
- 心跳机制:从服务器定期发送心跳包,主服务器回应
32. Redis的哨兵机制有什么作用?
答案:
- 监控:监控主从服务器的运行状态
- 自动故障转移:当主服务器宕机时,自动将从服务器提升为主服务器
- 通知:当监控的实例出现问题时,发送通知
- 配置提供:为客户端提供最新的主服务器地址
33. Redis集群的分片机制是什么?
答案:
- Redis集群采用虚拟槽分区,共16384个槽位
- 每个节点负责一部分槽位
- 通过哈希算法计算key属于哪个槽位
- CRC16(key) % 16384 = slot
34. Redis中的内存淘汰策略有哪些?
答案:
- noeviction:不淘汰,内存不足时拒绝写操作
- allkeys-lru:从所有key中删除最近最少使用的key
- volatile-lru:从设置了过期时间的key中删除最近最少使用的key
- allkeys-random:从所有key中随机删除
- volatile-random:从设置了过期时间的key中随机删除
- volatile-ttl:删除剩余生存时间最短的key
- volatile-lfu:从设置了过期时间的key中删除最不经常使用的key
- allkeys-lfu:从所有key中删除最不经常使用的key
35. Redis与Memcached的区别?
答案:
- 数据类型:Redis支持丰富的数据类型,Memcached只支持String
- 持久化:Redis支持持久化,Memcached不支持
- 内存管理:Redis使用自己的内存分配器,Memcached使用slab分配机制
- 原子操作:Redis支持更多的原子操作
- 集群:Redis原生支持集群,Memcached需要客户端实现分布式
- 事务:Redis支持简单事务,Memcached不支持
以上面试题涵盖了Java、Spring、SpringMVC、SpringBoot和Redis的核心知识点,希望对您有所帮助!