Skip to main content

常见面试题

以下是一些常见的Java面试题及解答思路,涵盖基础知识、高级特性、框架和项目经验等方面:

一、基础知识

1. 面向对象编程(OOP)

问题:什么是面向对象编程?Java有哪些特性体现了OOP?
解答思路

  • 核心概念:封装、继承、多态、抽象。
  • 结合Java代码举例:
    • 封装:通过private修饰符隐藏类的内部状态,提供public方法访问。
    • 继承:使用extends关键字实现类的复用。
    • 多态:通过接口或抽象类实现方法的动态绑定(如List list = new ArrayList())。
    • 抽象:使用abstract关键字定义抽象类或方法。

2. String、StringBuilder、StringBuffer的区别

解答思路

  • String:不可变对象,每次操作都会生成新对象,适合少量字符串操作。
  • StringBuilder:可变对象,非线程安全,性能高(推荐在单线程环境使用)。
  • StringBuffer:可变对象,线程安全(内部方法用synchronized修饰),性能低。
  • 场景选择:循环中拼接字符串用StringBuilder,多线程环境用StringBuffer

3. 自动装箱与拆箱

问题:解释Integer i = 10int j = i的过程。
解答思路

  • 装箱Integer i = 10 等价于 Integer i = Integer.valueOf(10)
  • 拆箱int j = i 等价于 int j = i.intValue()
  • 注意点Integer缓存池(默认范围-128~127),如Integer a = 100; Integer b = 100; a==b返回true

二、集合框架

1. HashMap的工作原理(Java 8+)

解答思路

  • 数据结构:数组+链表+红黑树(当链表长度≥8且数组长度≥64时,链表转为红黑树)。
  • put过程
    1. 计算key的hash值,定位数组索引。
    2. 若索引位置为空,直接插入;否则遍历链表/红黑树,存在相同key则覆盖,否则插入。
  • 扩容机制:当元素数量超过阈值(容量×负载因子,默认0.75)时,数组扩容为原来的2倍。
  • 线程安全:非线程安全,多线程环境用ConcurrentHashMap

2. ArrayList vs LinkedList

解答思路

  • 底层结构
    • ArrayList:动态数组,支持随机访问(O(1)),插入/删除效率低(O(n))。
    • LinkedList:双向链表,插入/删除效率高(O(1)),随机访问效率低(O(n))。
  • 适用场景:频繁随机访问用ArrayList,频繁插入删除用LinkedList

三、多线程与并发

1. synchronized与ReentrantLock的区别

解答思路

  • 语法层面
    • synchronized:Java内置关键字,自动释放锁(代码块/方法结束时)。
    • ReentrantLock:JDK类,需手动调用lock()unlock()
  • 功能特性
    • ReentrantLock:可中断锁、公平锁、尝试锁(tryLock())。
  • 性能
    • JDK 6+对synchronized优化(偏向锁、轻量级锁),性能接近ReentrantLock

2. 线程池的核心参数及工作流程

解答思路

  • 核心参数ThreadPoolExecutor):
    • corePoolSize:核心线程数。
    • maximumPoolSize:最大线程数。
    • workQueue:任务队列(如LinkedBlockingQueue)。
    • keepAliveTime:空闲线程存活时间。
    • RejectedExecutionHandler:拒绝策略(如AbortPolicy)。
  • 工作流程
    1. 提交任务,若核心线程未满,创建新线程执行。
    2. 若核心线程已满,任务入队。
    3. 若队列已满且线程数未达最大,创建新线程执行。
    4. 若线程数已达最大,触发拒绝策略。

四、JVM底层原理

1. JVM内存区域划分

解答思路

  • 堆(Heap):存储对象实例,线程共享,可分为新生代(Eden、Survivor)和老年代。
  • 栈(Stack):存储局部变量和方法调用帧,线程私有。
  • 方法区(Method Area):存储类信息、常量池等,线程共享(Java 8后改为元空间MetaSpace)。
  • 程序计数器(PC Register):记录当前线程执行的字节码行号。
  • 本地方法栈(Native Method Stack):为Native方法服务。

2. 垃圾回收(GC)机制

解答思路

  • 可达性分析:从GC Roots(如栈变量、静态变量)出发,标记不可达对象。
  • 垃圾收集算法
    • 标记-清除(Mark-Sweep):产生内存碎片。
    • 标记-整理(Mark-Compact):避免碎片。
    • 复制(Copying):新生代常用(Eden:Survivor=8:1:1)。
  • 垃圾收集器
    • 新生代:Serial、ParNew、Parallel Scavenge。
    • 老年代:CMS、Serial Old、Parallel Old。
    • 全堆:G1、ZGC。

五、框架与工具

1. Spring框架的核心特性

解答思路

  • IOC(控制反转):通过XML或注解配置,由容器管理对象的创建和依赖注入。
  • AOP(面向切面编程):通过动态代理(JDK或CGLIB)实现横切关注点(如日志、事务)。
  • 事务管理:声明式事务(基于AOP)和编程式事务。
  • MVCDispatcherServlet处理请求,@Controller@RequestMapping注解。

2. MyBatis与Hibernate的区别

解答思路

  • ORM程度
    • MyBatis:半ORM,需手动编写SQL,灵活控制查询。
    • Hibernate:全ORM,通过对象映射自动生成SQL,适合快速开发。
  • 适用场景
    • MyBatis:复杂SQL场景(如报表)。
    • Hibernate:业务逻辑简单、对象关系复杂的场景。

六、项目经验与场景题

1. 如何优化高并发系统?

解答思路

  • 前端:静态资源CDN、页面缓存、懒加载。
  • 服务端
    • 负载均衡(Nginx、LVS)。
    • 异步处理(消息队列RabbitMQ/Kafka)。
    • 限流熔断(Sentinel、Hystrix)。
  • 存储层
    • 缓存(Redis)。
    • 分库分表(ShardingSphere)。
    • 读写分离。

2. 如何解决分布式事务问题?

解答思路

  • 刚性事务:2PC(两阶段提交)、3PC(三阶段提交)。
  • 柔性事务
    • TCC(Try-Confirm-Cancel)。
    • 补偿事务(Saga模式)。
    • 最终一致性(基于消息队列)。

七、算法与数据结构

1. 手写快速排序

解答思路

public void quickSort(int[] arr, int left, int right) {
if (left < right) {
int pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
}

private int partition(int[] arr, int left, int right) {
int pivot = arr[right];
int i = left - 1;
for (int j = left; j < right; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, right);
return i + 1;
}

private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

2. 设计LRU缓存

解答思路

  • 使用LinkedHashMap实现,重写removeEldestEntry()方法:
import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;

public LRUCache(int capacity) {
super(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
};
}
}

八、总结

面试时需注意:

  1. 清晰表达思路:先解释概念,再结合代码或场景举例。
  2. 深入源码或原理:如HashMap的红黑树转换条件、synchronized的锁升级过程。
  3. 关联实际项目:用项目中的案例说明技术选择或问题解决过程。
  4. 对答如流的“高频题”:HashMap、多线程、JVM GC、Spring原理。