在Java技术复试面试中,面试官通常会问一些涉及基础知识、框架原理以及系统设计等方面的问题。下面是针对常见面试问题的详细解答,帮助你高效准备面试。编辑
1. 介绍集合
Java中的集合框架主要由三大部分组成:Collection 、Map 和Iterator 。每个部分提供了不同的数据存储结构和操作方法。编辑
-
Collection :是所有集合的根接口,主要包括:
List
、Set
、Queue
、Deque
等。-
List :有序、可重复的集合(如
ArrayList
、LinkedList
)。 -
Set :无序、不允许重复元素的集合(如
HashSet
、TreeSet
)。 -
Queue :队列,先进先出(FIFO),如
PriorityQueue
。
-
-
Map :映射接口,存储键值对(如
HashMap
、TreeMap
)。-
HashMap :基于哈希表实现,允许null键和null值。
-
TreeMap:基于红黑树实现,按键值排序。
-
-
Iterator :用于遍历集合元素的接口,支持
hasNext()
和next()
等方法。编辑
2. List的并发问题
List
是一个常用的集合,尤其是ArrayList
,但在多线程环境下使用List
时会面临并发问题,常见的问题有:
- ConcurrentModificationException :当多个线程同时修改
List
时,会导致该异常。 - 数据不一致性:例如,线程A读取数据时,线程B修改了数据,导致读取到的内容不一致。
为了解决并发问题,可以使用:
CopyOnWriteArrayList
:线程安全的List
实现。Vector
:虽然是线程安全的,但性能较低,已经不推荐使用。- 使用外部锁(如
synchronized
)保证线程安全。
3. Set是否有序?去重原理?如何有序?
-
是否有序 :
Set
本身并不保证有序性。具体实现中:-
HashSet :无序,元素的顺序取决于哈希算法。
-
LinkedHashSet :有序,按照插入顺序保存元素。
-
TreeSet:有序,基于红黑树实现,按自然顺序或者自定义排序规则排序元素。
-
-
去重原理 :
Set
通过哈希值判断元素是否重复。在HashSet
中,通过hashCode()
和equals()
方法判断元素是否相同。编辑
4. 异常机制
Java的异常机制分为两类:
- Checked Exception (检查型异常):需要显式捕获或声明的异常(如
IOException
)。 - Unchecked Exception (非检查型异常):运行时异常,不需要显式捕获或声明(如
NullPointerException
、ArithmeticException
)。
Java通过try-catch
语句来捕获异常,finally
块用于执行清理工作。常见的异常处理流程包括:
java
try {
// 可能引发异常的代码
} catch (ExceptionType e) {
// 异常处理代码
} finally {
// 清理代码,无论是否发生异常
}
5. 线程的5大状态
Java中的线程有五种状态:
- 新建(New) :线程对象被创建,但尚未调用
start()
方法。 - 就绪(Runnable):线程准备好运行,但尚未获得CPU的时间片。
- 运行(Running):线程正在执行。
- 阻塞(Blocked):线程等待获取锁资源。
- 终止(Terminated):线程执行完毕或因异常退出。
6. 线程的创建方式
Java中创建线程有三种方式:
-
继承
Thread
类 :重写run()
方法,调用start()
启动线程。
java class MyThread extends Thread { public void run() { System.out.println("Thread is running"); } } MyThread thread = new MyThread(); thread.start();
-
实现
Runnable
接口 :通过实现run()
方法来定义线程的工作内容。
java class MyRunnable implements Runnable { public void run() { System.out.println("Thread is running"); } } Thread thread = new Thread(new MyRunnable()); thread.start();
-
使用
Callable
和ExecutorService
:返回值形式,适用于任务有返回结果时。
7. 线程池原理
线程池通过复用已有线程来执行任务,减少了频繁创建和销毁线程的开销。主要原理包括:
- 核心线程数:始终存在的线程数。
- 最大线程数:线程池能容纳的最大线程数。
- 任务队列:用于存放待执行的任务。
- 线程池的拒绝策略 :如
ThreadPoolExecutor.AbortPolicy
、ThreadPoolExecutor.DiscardPolicy
等。
常见的线程池实现:
ExecutorService
接口,常用实现为ThreadPoolExecutor
。
8. 谈谈双亲委派机制
双亲委派机制是类加载器的工作机制。在加载类时,Java的类加载器会遵循以下规则:
- 委托机制 :每个类加载器都有一个父类加载器。当加载一个类时,当前加载器首先请求父类加载器加载该类,直到最顶层的
Bootstrap ClassLoader
。 - 好处 :保证了Java核心库(如
rt.jar
)的类不会被覆盖,确保了JVM的稳定性。
9. 垃圾回收算法介绍
Java的垃圾回收算法主要有以下几种:
- 标记-清除算法:标记所有需要回收的对象,然后清除它们。缺点是可能产生内存碎片。
- 复制算法:将内存分为两块,每次使用一块。回收时将活动对象复制到另一块内存中。
- 标记-整理算法:标记需要回收的对象,然后将活动对象移到一块连续的内存区域,避免内存碎片。
- 分代回收算法:将堆内存分为年轻代、老年代和永久代,不同代使用不同的回收策略。
10. 谈谈Spring
Spring是一个开源框架,广泛用于Java应用的开发。Spring的核心特性包括:
- IoC(控制反转)容器:通过依赖注入(DI)管理对象的创建和生命周期。
- AOP(面向切面编程):通过代理机制实现横切关注点的功能,如日志、事务等。
- 事务管理:提供声明式事务管理,使得事务的处理变得简单。
- Spring MVC:Web开发模块,通过分层架构实现MVC模式。
11. 前端发来一条请求,Spring是怎么处理的
当前端发来请求,Spring会按照以下流程进行处理:
- 前端请求:浏览器发起HTTP请求。
- DispatcherServlet :Spring的核心控制器,它接收到请求后,会根据配置文件(如
web.xml
)将请求转发给相应的Controller。 - HandlerMapping:查找合适的Controller处理请求。
- Controller :执行请求逻辑,返回Model和View(通过
@RequestMapping
映射)。 - ViewResolver:根据返回的View名称解析出具体的视图(如JSP页面)。
- 响应返回:将视图渲染后返回给前端浏览器。
12. Redis的OOM溢出原因和解决方案
- 原因 :当Redis的内存使用超过配置的
maxmemory
限制时,会发生OOM(Out of Memory)错误。常见的原因包括数据过多、配置不合理或缓存策略不当。 - 解决方案 :
- 调整
maxmemory
配置 :限制Redis使用的最大内存。 - 使用LRU策略 :根据最近最少使用(Least Recently Used)策略淘汰数据。
- 定期清理过期数据:通过设置过期时间来防止缓存堆积。
- 调整
13. Redis的缓存穿透
缓存穿透指的是请求的数据在缓存和数据库中都不存在,这种请求会直接到达数据库,造成数据库的压力。解决方案:
- 使用布隆过滤器来过滤无效请求。
- 对不存在的数据缓存一个空值,设置较短的过期时间,防止重复查询数据库。
14. 为什么用RocketMQ,为什么不用其他的MQ?
RocketMQ是一个分布式消息中间件,广泛用于高吞吐量和低延迟的消息传递。相比其他消息队列系统,RocketMQ具有以下优势:
- 高吞吐量:RocketMQ支持高效的消息队列管理,能够处理大规模数据流动,且支持大批量的消息发送和接收。
- 分布式事务支持:RocketMQ提供了分布式事务的支持,能够确保消息一致性,适合复杂的业务场景。
- 灵活的消息消费方式:支持点对点、发布/订阅等多种消费模式,提供灵活的消息消费和传输机制。
- 高可靠性和高可用性:RocketMQ设计了多副本机制,保证了消息的可靠性,即使部分节点宕机,系统仍能继续运行。
与其他消息中间件如Kafka、RabbitMQ等相比,RocketMQ在高吞吐量、低延迟以及分布式事务模型的支持上有一定优势。
15. RocketMQ的分布式事务模型
RocketMQ的分布式事务模型基于 "3-phase commit"(三阶段提交协议)。其基本流程如下:
- 事务消息发送阶段:生产者发送消息到RocketMQ的事务消息队列,并标记该消息为"半消息"。
- 事务消息执行阶段:消息生产者执行本地事务操作,并根据事务执行的结果提交或回滚消息。
- 事务消息确认阶段:如果本地事务成功,则提交消息;如果失败,则回滚消息。
这个机制确保了消息的可靠性和一致性,适用于分布式系统中的事务管理。
16. Dubbo的原理
Dubbo是一个高性能的Java RPC框架,用于实现分布式服务的通信。其核心原理包括:
- 服务暴露和引用:Dubbo将服务暴露到网络中,客户端可以通过代理模式引用远程服务。
- 协议与序列化:Dubbo使用高效的通信协议(如HTTP、Dubbo协议)和序列化机制(如Hessian)来传输数据。
- 注册中心:Dubbo通过注册中心(如Zookeeper)进行服务发现和负载均衡,客户端可以动态发现可用的服务提供者。
- 调用与返回:Dubbo的客户端通过代理发起RPC调用,服务端接收到请求后,执行业务逻辑并返回结果。
Dubbo的设计模式非常注重解耦,提供了高效的异步通信和负载均衡能力,适用于大规模分布式系统。
总结:
RocketMQ因其高吞吐量、低延迟以及对分布式事务的支持,特别适合需要高可靠性和可扩展性的场景。Dubbo作为一个轻量级的RPC框架,提供了简单而高效的分布式服务调用方式,广泛应用于微服务架构中。