Java面试核心知识点:从基础到框架的深度解析
1. Java面试全攻略:从基础到框架的深度解析
作为一名经历过数十场技术面试的Java开发者,我深知面试准备的重要性。这份面试题汇总不仅是我个人经验的总结,更是结合了近年来一线互联网公司的真实面试题整理而成。无论你是初入职场的新人,还是准备跳槽的资深工程师,系统性地掌握这些核心知识点都能让你在面试中游刃有余。
2. Java基础核心20问
2.1 JDK与JRE的本质区别
JDK(Java Development Kit)是Java开发工具包,包含JRE和开发工具(如编译器javac、调试工具jdb等)。而JRE(Java Runtime Environment)仅包含运行Java程序所需的JVM和核心类库。简单来说,开发者需要安装JDK,而最终用户只需JRE即可运行Java程序。
实际开发中常见误区:在服务器环境只安装了JRE导致无法使用javac等工具。建议生产环境也安装JDK以便排查问题。
2.2 ==与equals的深度比较
==比较的是对象的内存地址,而equals比较的是对象的内容。但要注意Object类中默认的equals实现其实就是==比较,所以自定义类需要重写equals方法。重写equals时必须同时重写hashCode(),否则会导致HashMap等集合类工作异常。
// 典型equals方法实现 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyClass myClass = (MyClass) o; return field1 == myClass.field1 && Objects.equals(field2, myClass.field2); }2.3 hashCode与equals的契约关系
当两个对象的hashCode()相同时,equals()不一定为true(哈希冲突)。但equals()为true时,hashCode()必须相同。这个契约关系是Java集合框架正常工作的基础。违反这一规则会导致HashSet/HashMap等集合无法正确识别相同对象。
2.4 final关键字的三种应用场景
- final类:不可被继承,如String类
- final方法:不可被重写
- final变量:基本类型值不可变,引用类型引用不可变(但对象内容可变)
在并发编程中,final变量能保证可见性,是一种简单的线程安全手段。
2.5 字符串处理最佳实践
String是不可变类,每次修改都会创建新对象。对于频繁修改的场景应使用StringBuilder(非线程安全)或StringBuffer(线程安全)。JDK9后字符串底层改用byte[]存储,并引入了紧凑字符串优化。
// 字符串反转的几种方式 String str = "hello"; new StringBuilder(str).reverse().toString(); // 最佳实践 new StringBuffer(str).reverse().toString(); // 线程安全版3. Java容器深度解析
3.1 HashMap实现原理与优化
JDK8中的HashMap采用数组+链表+红黑树结构。当链表长度超过8且数组长度大于64时,链表会转为红黑树。扩容因子默认为0.75,即元素数量达到容量的75%时进行2倍扩容。
// HashMap初始化最佳实践 Map<String, Integer> map = new HashMap<>(16); // 给定初始容量避免频繁扩容3.2 ArrayList与LinkedList的性能对比
ArrayList基于动态数组,随机访问快(O(1))但插入删除慢(O(n));LinkedList基于双向链表,插入删除快(O(1))但随机访问慢(O(n))。实际开发中,查询多用ArrayList,频繁增删考虑LinkedList。
经验之谈:90%场景下ArrayList表现更好,因为现代CPU缓存对数组遍历有优化。只有当头部频繁插入时才考虑LinkedList。
3.3 线程安全容器选型指南
- Hashtable:全表锁,性能差
- Collections.synchronizedMap:包装器模式,性能一般
- ConcurrentHashMap:分段锁(JDK7)或CAS+synchronized(JDK8),高并发首选
- CopyOnWriteArrayList:读多写少场景适用
4. 并发编程核心知识点
4.1 线程池的7个核心参数
ThreadPoolExecutor( int corePoolSize, // 核心线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 空闲线程存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 工作队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略 )4.2 synchronized底层实现原理
JDK6之后synchronized进行了重大优化,引入了偏向锁、轻量级锁、重量级锁的升级机制:
- 偏向锁:MarkWord记录线程ID,适用于单线程访问场景
- 轻量级锁:通过CAS竞争MarkWord
- 重量级锁:向操作系统申请互斥量
4.3 volatile的内存语义
volatile保证可见性和有序性(禁止指令重排序),但不保证原子性。其底层通过内存屏障实现:
- 写操作前插入StoreStore屏障
- 写操作后插入StoreLoad屏障
- 读操作前插入LoadLoad屏障
- 读操作后插入LoadStore屏障
5. Spring框架面试精要
5.1 IOC容器的启动流程
- 资源定位:找到配置文件
- 加载解析:将配置转化为BeanDefinition
- 注册:将BeanDefinition存入注册表
- 依赖注入:实例化Bean并解决依赖关系
- 初始化:执行init-method等回调
5.2 Spring事务传播行为详解
| 传播行为类型 | 说明 |
|---|---|
| REQUIRED(默认) | 当前有事务则加入,没有则新建 |
| REQUIRES_NEW | 新建事务,挂起当前事务 |
| NESTED | 嵌套事务,使用保存点实现 |
| SUPPORTS | 有事务则加入,没有则以非事务运行 |
| NOT_SUPPORTED | 以非事务方式运行,挂起当前事务 |
| MANDATORY | 必须在事务中运行,否则抛出异常 |
| NEVER | 必须在非事务中运行,否则抛异常 |
5.3 Spring MVC请求处理流程
- DispatcherServlet接收请求
- HandlerMapping找到处理器
- HandlerAdapter执行处理器
- 处理器返回ModelAndView
- ViewResolver解析视图
- 视图渲染并返回响应
6. 数据库与持久层技术
6.1 MyBatis缓存机制对比
| 缓存级别 | 作用范围 | 生命周期 | 开启方式 |
|---|---|---|---|
| 一级缓存 | SqlSession | 会话级别,默认开启 | 无需配置 |
| 二级缓存 | Mapper级别 | 应用级别,需手动配置 | 标签 |
踩坑提醒:二级缓存可能导致脏读,在分布式环境下建议使用Redis等集中式缓存替代。
6.2 MySQL索引优化原则
- 最左前缀原则:联合索引(a,b,c)只能用于a、ab、abc查询
- 避免在索引列上使用函数:WHERE YEAR(create_time)=2022会导致索引失效
- 使用覆盖索引减少回表
- 字符串字段建立前缀索引
- 区分度高的列适合建索引(区分度=不重复数/总数)
7. 分布式与微服务
7.1 Spring Cloud核心组件
- 服务注册发现:Eureka/Nacos
- 客户端负载均衡:Ribbon
- 声明式HTTP客户端:Feign
- 服务熔断降级:Hystrix/Sentinel
- 网关:Zuul/Gateway
- 配置中心:Config/Nacos
- 消息总线:Bus
7.2 RabbitMQ消息可靠性保证
- 生产者确认模式(publisher confirm)
- 消息持久化(deliveryMode=2)
- 消费者手动ACK
- 死信队列处理失败消息
- 集群镜像队列防止节点故障
8. JVM性能调优实战
8.1 内存区域与OOM分析
| 区域 | 作用 | 常见OOM原因 |
|---|---|---|
| 堆 | 对象实例 | 内存泄漏/大对象 |
| 方法区 | 类信息 | 动态生成类过多 |
| 虚拟机栈 | 方法调用 | 递归过深 |
| 本地方法栈 | Native方法 | JNI代码问题 |
| 程序计数器 | 执行位置 | 不会OOM |
8.2 GC算法与收集器选择
- Serial:单线程,适合客户端应用
- Parallel Scavenge:吞吐量优先
- CMS:低延迟,JDK9开始废弃
- G1:平衡型,JDK9默认
- ZGC:超低延迟,JDK15生产可用
调优经验:多数应用使用G1即可,-Xmx和-Xms设为相同值避免动态调整,Young区大小约占堆的1/3到1/2。
9. 设计模式实战案例
9.1 Spring中的设计模式应用
- 工厂模式:BeanFactory
- 代理模式:AOP实现
- 单例模式:Bean默认作用域
- 模板方法:JdbcTemplate
- 观察者模式:ApplicationEvent
- 适配器模式:HandlerAdapter
9.2 单例模式的7种实现
从最简单的饿汉式到复杂的枚举单例,需要考虑线程安全、序列化、反射攻击等问题。当前最佳实践是使用枚举实现:
public enum Singleton { INSTANCE; public void doSomething() { // ... } }10. 线上问题排查工具箱
10.1 Arthas常用命令
- dashboard:系统实时监控面板
- thread:查看线程堆栈
- jad:反编译类文件
- watch:方法执行数据观测
- trace:方法调用链路追踪
- ognl:执行ognl表达式
10.2 性能问题定位步骤
- top命令确认CPU/内存异常进程
- jps/jinfo查看Java进程基本信息
- jstack分析线程状态
- jmap/jstat分析内存使用
- arthas/btrace进行动态诊断
- 结合日志和Metrics定位根源
在实际面试中,除了正确回答问题外,展示解决问题的思路同样重要。比如被问到HashMap原理时,可以先讲基本结构,再延伸到线程安全问题,最后谈到ConcurrentHashMap的优化,这样能体现知识的系统性和深度。
