> 技术文档 > 国企央企Java后端面试八股文核心要点(面试必看!!!)_计算机国央企问八股文吗
国企央企Java后端面试八股文核心要点(面试必看!!!)_计算机国央企问八股文吗
网友:Bloger
技术文档
2025-08-08 10:56:37
模块一:Java 基础 (Java Basics)
1. ==
和 equals()
的核心区别是什么?
- 答案:
==
: 比较的是两个变量的值。
- 如果变量是基本数据类型(如
int
, char
),则比较它们存储的数值是否相等。
- 如果变量是引用类型(如
String
, Object
),则比较它们在内存中的地址是否相同,即是否指向同一个对象。
equals()
: 是 Object
类的一个方法,默认行为与 ==
相同(比较地址)。但是,很多类(如 String
, Integer
, Date
)都重写了 equals()
方法,用于比较两个对象的内容是否相同。
2. hashCode()
和 equals()
的关系是什么?为什么重写 equals()
通常要重写 hashCode()
?
- 答案:
- 关系:
- 如果两个对象通过
equals()
方法比较为 true
,那么它们的 hashCode()
值必须相同。
- 如果两个对象的
hashCode()
值相同,它们通过 equals()
方法比较不一定为 true
(这被称为哈希冲突)。
- 原因: 在使用哈希表结构的集合(如
HashMap
, HashSet
)时,系统会先通过 hashCode()
快速定位到对象可能存储的“桶”位置,然后再使用 equals()
方法确认该位置上是否存在内容相同的对象。如果只重写 equals()
而不重写 hashCode()
,会导致两个内容相同的对象产生不同的哈希码,违反了第一条原则,使得对象在哈希集合中无法被正确定位,可能导致“存不进”或“取不出”的问题。
3. String
、StringBuilder
和 StringBuffer
的区别是什么?
- 答案:
String
: 是不可变的(immutable)。每次对 String
对象进行修改时,都会创建一个新的 String
对象。
StringBuilder
: 是可变的,并且是非线程安全的。适用于单线程环境下对字符串进行频繁修改。
StringBuffer
: 是可变的,并且是线程安全的。方法用 synchronized
修饰,适用于多线程环境。
4. 谈谈Java的四种访问修饰符 (public
, protected
, default
, private
)。
- 答案:
public
: 公共的。任何地方都可以访问。
protected
: 受保护的。同一个包内、以及不同包的子类中可以访问。
default
(不写修饰符): 默认的/包私有的。只能在同一个包内访问。
private
: 私有的。只能在同一个类内部访问。
5. 什么是面向对象?请解释一下封装、继承和多态。
- 答案: 面向对象(OOP)是一种将现实世界抽象成程序中“对象”的编程思想。
- 封装 (Encapsulation): 将对象的属性和行为包装在一起,隐藏内部实现细节,通过公共接口访问。
- 继承 (Inheritance): 子类继承父类的属性和方法,实现代码复用。
- 多态 (Polymorphism): 同一个接口或方法,可以有多种不同的实现方式(重载和重写)。
6. 什么是Java的泛型?使用泛型有什么好处?
- 答案:
- 定义: 泛型允许在定义类、接口、方法时使用“类型参数”,在使用时才指定具体类型。
- 好处: 1. 类型安全(编译期检查);2. 代码复用;3. 消除强制类型转换。
7. Java的异常体系是怎样的?Error
和 Exception
的区别是什么?
- 答案:
- 体系: 根类是
Throwable
,它有两个子类:Error
和 Exception
。
Error
(错误): JVM自身的严重问题(如 OutOfMemoryError
),程序通常无法处理。
Exception
(异常): 程序可以处理的问题。分为:
- 受检异常 (Checked Exception): 编译器强制要求处理(如
IOException
)。
- 非受检异常 (Unchecked Exception) / 运行时异常 (RuntimeException): 编译器不强制处理,通常是逻辑错误(如
NullPointerException
)。
8. final
, finally
, finalize
三者有什么区别?
- 答案:
final
: 修饰符。修饰类(不能被继承)、方法(不能被重写)、变量(常量)。
finally
: 异常处理代码块。无论是否发生异常,都一定会被执行,通常用于释放资源。
finalize
: Object
的一个方法。对象被垃圾回收前可能调用,不推荐使用。
9. 请描述一下Java中的序列化和反序列化。
- 答案:
- 序列化 (Serialization): 将Java对象转换成字节序列的过程,便于传输或存储。需实现
Serializable
接口。
- 反序列化 (Deserialization): 将字节序列恢复成Java对象的过程。
10. int
和 Integer
的区别是什么?自动装箱和拆箱是如何工作的?
- 答案:
- 区别:
int
是基本数据类型,默认值是 0
。Integer
是包装类(对象),默认值是 null
。
- 自动装箱 (Autoboxing): 将基本类型自动转换为包装类对象。
Integer i = 100;
- 自动拆箱 (Unboxing): 将包装类对象自动转换为基本类型。
int n = i;
模块二:Java 集合框架
1. ArrayList
和 LinkedList
的底层实现和各自的优缺点是什么?
- 答案:
ArrayList
: 基于动态数组。查询快 (O(1)),增删慢 (O(n))。
LinkedList
: 基于双向链表。增删快 (O(1)),查询慢 (O(n))。
2. HashMap
的底层数据结构是什么?(JDK 1.7 vs 1.8)
- 答案:
- JDK 1.7: 数组 + 链表。
- JDK 1.8: 数组 + 链表 + 红黑树。当链表长度超过阈值(8)时,会转换为红黑树以提高查询效率。
3. HashMap
的 put
方法的执行过程是怎样的?
- 答案:
- 计算
key
的 hashCode()
并确定在数组中的索引。
- 如果该位置为空,直接插入。
- 如果该位置不为空(哈希冲突),遍历链表或红黑树。
- 若找到
key
相同的节点,则替换 value
。
- 若未找到,则将新节点插入链表尾部(或红黑树中)。
4. HashMap
是如何解决哈希冲突的?
- 答案: 主要使用链地址法。即将哈希值相同的节点链接成一个链表(或红黑树)。
5. HashMap
和 Hashtable
的区别是什么?
- 答案:
- 线程安全性:
HashMap
非线程安全,Hashtable
线程安全。
null
值支持: HashMap
允许一个 null
key 和多个 null
value。Hashtable
不允许任何 null
。
- 效率:
HashMap
效率更高。
6. ConcurrentHashMap
是如何保证线程安全的?(JDK 1.7 vs 1.8)
- 答案:
- JDK 1.7: 分段锁(Segment)。将数据分成多个段,锁住段来进行操作,提高了并发度。
- JDK 1.8: CAS (Compare-And-Swap) +
synchronized
。对数组的头节点加锁,锁的粒度更细,性能更好。
7. HashSet
是如何保证元素唯一的?
- 答案:
HashSet
的底层依赖于 HashMap
。它将存入的元素作为 HashMap
的 key
来存储,利用 HashMap
的 key
唯一性来保证元素的唯一。
模块三:多线程与并发
1. 进程和线程的区别是什么?
- 答案: 进程是操作系统资源分配的基本单位,有独立的内存空间。线程是CPU任务调度的基本单位,共享进程的资源,开销更小。
2. 在Java中创建线程有哪几种方式?
- 答案: 1. 继承
Thread
类; 2. 实现 Runnable
接口 (推荐); 3. 实现 Callable
接口 (可有返回值)。
3. 线程有哪些状态?它们之间是如何转换的?
- 答案: 六种状态:NEW (新建), RUNNABLE (可运行), BLOCKED (阻塞), WAITING (等待), TIMED_WAITING (计时等待), TERMINATED (终止)。
4. sleep()
和 wait()
方法有什么区别?
- 答案:
- 所属类:
sleep()
是 Thread
的静态方法,wait()
是 Object
的方法。
- 锁的释放:
sleep()
不释放锁,wait()
释放锁。
- 唤醒方式:
sleep()
时间到后自动唤醒,wait()
需由其他线程调用 notify()
或 notifyAll()
唤醒。
5. 为什么要使用线程池?线程池的核心参数有哪些?
- 答案:
- 好处: 降低资源消耗(复用线程),提高响应速度,提高线程的可管理性。
- 核心参数:
corePoolSize
(核心线程数), maximumPoolSize
(最大线程数), keepAliveTime
(空闲线程存活时间), workQueue
(工作队列), handler
(拒绝策略)。
6. synchronized
关键字的底层原理是什么?
- 答案: 基于监视器锁(Monitor) 实现。JVM通过
monitorenter
和 monitorexit
字节码指令来获取和释放Monitor。包含偏向锁、轻量级锁、重量级锁的锁升级过程。
7. synchronized
和 ReentrantLock
有什么区别?
- 答案:
- 实现:
synchronized
是JVM关键字,ReentrantLock
是API层面的类。
- 功能:
ReentrantLock
功能更丰富,支持可中断等待、公平锁和绑定多个Condition。
- 使用:
synchronized
自动释放锁,ReentrantLock
需手动在 finally
块中释放锁。
8. 什么是CAS(比较并交换)?它有什么问题?
- 答案:
- 定义: 一种无锁化的原子操作,当内存值与预期值相同时才进行更新。
- 问题: 1. ABA问题(可通过版本号解决); 2. 自旋开销大; 3. 只能保证一个共享变量的原子操作。
9. 谈谈你对 volatile
关键字的理解。
- 答案:
volatile
是轻量级同步机制。主要作用:1. 保证可见性(修改立刻对其他线程可见); 2. 禁止指令重排序。注意:volatile
不保证原子性。
10. ThreadLocal
是什么?它的实现原理是什么?
- 答案:
- 是什么: 提供线程内的局部变量,实现线程间数据隔离。
- 原理: 每个
Thread
对象内部都有一个 ThreadLocalMap
,key
是 ThreadLocal
对象本身,value
是要存储的变量副本。
模块四:JVM (Java 虚拟机)
1. 请详细描述一下JVM的内存模型(运行时数据区)。
- 答案:
- 线程共享区域:
- 堆 (Heap): 存放对象实例和数组,是GC主要区域。
- 方法区 (Method Area): 存储类信息、常量、静态变量等。
- 线程私有区域:
- 虚拟机栈 (VM Stack): 存储方法调用的栈帧(局部变量等)。
- 本地方法栈 (Native Method Stack): 为Native方法服务。
- 程序计数器 (PC Register): 记录当前线程执行的字节码行号。
2. Java对象在内存中是如何创建的?
- 答案: 1. 类加载检查; 2. 在堆中分配内存; 3. 初始化零值; 4. 设置对象头; 5. 执行构造函数。
3. 堆和栈的区别是什么?
- 答案:
- 管理: 栈自动分配释放,堆由GC管理。
- 空间: 栈空间小,堆空间大。
- 共享性: 栈线程私有,堆线程共享。
- 存储: 栈存基本类型和引用,堆存对象实例。
4. 如何判断一个对象是否“已死”?
- 答案:
- 引用计数法: 存在循环引用问题,主流JVM不采用。
- 可达性分析算法: 从\"GC Roots\"开始搜索,无法到达的对象即为“已死”。这是主流方法。
5. 简述一下Java的垃圾回收机制(GC)。
- 答案: GC是Java提供的自动内存管理机制,用于自动识别和回收不再使用的内存,防止内存泄漏。
6. 你知道哪些常见的垃圾回收算法?
- 答案:
- 标记-清除 (Mark-Sweep): 会产生内存碎片。
- 复制 (Copying): 高效但浪费一半内存,用于新生代。
- 标记-整理 (Mark-Compact): 解决了碎片问题,用于老年代。
- 分代收集 (Generational Collection): 商业虚拟机通用算法,根据对象存活周期不同采用不同算法。
7. 你知道哪些垃圾回收器?它们各自的特点是什么?
- 答案:
- Serial: 单线程,客户端模式默认。
- Parallel Scavenge: 多线程,追求高吞吐量,JDK 8默认新生代收集器。
- CMS: 并发收集,追求最短停顿时间,用于互联网应用。
- G1: 面向服务端,可预测停顿时间模型。
8. 什么是双亲委派模型?它有什么好处?
- 答案:
- 是什么: 类加载请求会先委派给父加载器,只有父加载器无法加载时,子加载器才会尝试自己加载。
- 好处: 1. 避免类的重复加载; 2. 保证安全性(防止核心API被篡改)。
9. 谈谈你对类加载过程的理解。
- 答案: 主要包括五个阶段:加载 (Loading) -> 验证 (Verification) -> 准备 (Preparation) -> 解析 (Resolution) -> 初始化 (Initialization)。
模块五:常用框架 (Spring / SpringBoot / MyBatis)
Spring
1. 谈谈你对Spring IOC(控制反转)和AOP(面向切面编程)的理解。
- 答案:
- IOC: 控制反转,将对象的创建和管理权交给Spring容器。DI(依赖注入)是其实现方式。
- AOP: 面向切面编程,将公共功能(如日志、事务)与业务代码分离,实现解耦。
2. AOP主要用在哪些场景?
- 答案: 统一的日志记录、声明式事务管理、权限控制、性能监控等。
3. Spring Bean的生命周期是怎样的?
- 答案: 实例化 -> 填充属性 -> 初始化 (
InitializingBean
/init-method
) -> Bean可用 -> 销毁 (DisposableBean
/destroy-method
)。
4. Spring中的事务是如何实现的?事务的传播行为有哪些?
- 答案:
- 实现: 基于AOP和动态代理。
- 传播行为:
REQUIRED
(默认,有则加入,无则创建), REQUIRES_NEW
(总是创建新事务), SUPPORTS
(有则加入,无则非事务运行)。
5. @Autowired
和 @Resource
注解的区别是什么?
- 答案:
@Autowired
: Spring提供,默认按类型 (byType) 装配。
@Resource
: Java规范提供,默认按名称 (byName) 装配。
SpringBoot
1. SpringBoot相比Spring有哪些核心优点?
- 答案: 1. 起步依赖 (Starter) 简化配置; 2. 自动配置 (Auto-configuration); 3. 内嵌服务器 (Tomcat等)。
2. SpringBoot的自动配置原理是什么?
- 答案: 核心是
@EnableAutoConfiguration
注解。它会加载所有依赖包中 META-INF/spring.factories
文件里定义的配置类,再根据 @ConditionalOn...
等条件注解判断是否要将Bean注册到容器。
3. SpringBoot的启动流程是怎样的?
- 答案:
SpringApplication.run()
-> 创建SpringApplication
实例 -> 准备和刷新应用上下文 (refreshContext
) -> 创建和初始化所有Bean -> 启动内嵌服务器。
MyBatis
1. MyBatis中 ${}
和 #{}
的区别是什么?
- 答案:
#{}
: 预编译处理,使用 ?
占位符,可以有效防止SQL注入。
${}
: 字符串替换,直接拼接SQL,有SQL注入风险,用于动态表名等场景。
2. MyBatis的一级缓存和二级缓存是什么?
- 答案:
- 一级缓存:
SqlSession
级别,默认开启,无法关闭。
- 二级缓存:
Mapper Namespace
级别,多个 SqlSession
可共享,需手动开启。
模块六:数据库 (Database - 以MySQL为例)
1. 数据库事务的四大特性(ACID)是什么?
- 答案:
- A (Atomicity) - 原子性: 要么都成功,要么都失败。
- C (Consistency) - 一致性: 事务前后,数据库状态保持一致。
- I (Isolation) - 隔离性: 并发事务互不干扰。
- D (Durability) - 持久性: 事务一旦提交,改变就是永久的。
2. 事务的四种隔离级别是什么?它们分别解决了什么问题?
- 答案:
- 读未提交: 导致脏读。
- 读已提交: 解决脏读,但导致不可重复读。
- 可重复读 (MySQL默认): 解决脏读、不可重复读,但导致幻读。
- 可串行化: 解决所有问题,但性能最差。
3. 什么是数据库索引?它的优缺点是什么?
- 答案:
- 是什么: 一种提高查询效率的数据结构,用空间换时间。
- 优点: 加快检索速度。
- 缺点: 占用空间,降低增、删、改的速度。
4. 索引的底层数据结构是什么?为什么选择B+树?
- 答案: 是 B+树。原因:1. 层高低,减少I/O次数; 2. 查询性能稳定; 3. 叶子节点链表,更适合范围查询。
5. 什么情况下索引会失效?
- 答案: 1.
LIKE
以 %
开头; 2. 对索引列进行函数操作或计算; 3. OR
连接的条件中有一列无索引; 4. 数据类型不匹配。
6. SQL查询如何进行优化?
- 答案: 1. 使用
EXPLAIN
分析查询; 2. 为 WHERE
, ORDER BY
, JOIN
的列建索引; 3. 避免 SELECT *
; 4. 避免在 WHERE
中对索引列操作。
7. INNER JOIN
, LEFT JOIN
, RIGHT JOIN
的区别是什么?
- 答案:
INNER JOIN
: 只返回两表匹配的记录。
LEFT JOIN
: 返回左表所有记录和右表匹配的记录。
RIGHT JOIN
: 返回右表所有记录和左表匹配的记录。
8. CHAR
和 VARCHAR
的区别是什么?
- 答案:
CHAR
: 定长字符串,速度快但浪费空间。
VARCHAR
: 可变长字符串,节省空间但速度可能稍慢。
模块七:中间件 (Middleware - Redis & MQ)
Redis
1. Redis有哪些常见的数据类型?
- 答案:
String
(字符串), List
(列表), Hash
(哈希), Set
(集合), Sorted Set
(有序集合)。
2. Redis为什么这么快?
- 答案: 1. 完全基于内存操作; 2. 单线程模型避免上下文切换和锁竞争; 3. I/O多路复用技术 (如epoll); 4. 高效的数据结构。
3. Redis的持久化机制有哪几种?
- 答案:
- RDB (快照): 在指定时间间隔内生成数据快照,恢复快但可能丢失数据。
- AOF (日志追加): 记录所有写命令,数据安全性高但文件大、恢复慢。
4. 什么是缓存穿透、缓存击穿和缓存雪崩?如何解决?
- 答案:
- 穿透: 查询不存在的数据。解决: 缓存空值、布隆过滤器。
- 击穿: 热点Key失效。解决: 加互斥锁、热点数据永不过期。
- 雪崩: 大量Key同时失效。解决: 过期时间加随机值、构建高可用缓存。
消息队列 (Message Queue)
1. 为什么要使用消息队列?
2. 消息队列如何保证消息的可靠性投递?
- 答案: 从三方面保证:
- 生产者 -> MQ: 发送方确认机制。
- MQ自身: 配置持久化。
- MQ -> 消费者: 消费方确认机制。
3. 你知道哪些常见的消息队列产品?
- 答案: RabbitMQ (功能全面), RocketMQ (阿里开源,性能强), Kafka (高吞吐量,用于大数据)。
模块八:计算机网络
1. 描述一下TCP的三次握手和四次挥手过程。
- 答案:
- 三次握手: 1. Client
SYN
-> Server; 2. Server SYN+ACK
-> Client; 3. Client ACK
-> Server.
- 四次挥手: 双方各发送一个
FIN
和一个 ACK
。
2. 为什么TCP握手是三次,而不是两次或四次?
- 答案: 为了防止已失效的历史连接请求突然传到服务器,导致服务器资源浪费。三次已足够验证双方收发能力。
3. TCP和UDP的核心区别和适用场景是什么?
- 答案:
- 区别: TCP面向连接、可靠、慢;UDP无连接、不可靠、快。
- 场景: TCP用于文件传输、网页浏览;UDP用于在线视频、语音通话。
4. 在浏览器中输入一个URL后,发生了什么?
- 答案: DNS解析 -> 建立TCP连接 -> 发送HTTP请求 -> 服务器响应 -> 浏览器解析渲染 -> 断开TCP连接。
5. 常见的HTTP状态码有哪些?
- 答案:
200 OK
(成功)
301 Moved Permanently
(永久重定向)
403 Forbidden
(禁止访问)
404 Not Found
(未找到)
500 Internal Server Error
(服务器内部错误)
502 Bad Gateway
(网关错误)
6. HTTP和HTTPS的区别是什么?HTTPS是如何保证安全的?
- 答案:
- 区别: HTTP明文传输,不安全;HTTPS通过SSL/TLS加密传输,安全。HTTPS需要申请数字证书。
- 安全原理: 通过数据加密(对称加密)、身份认证(非对称加密+数字证书)、数据完整性(消息摘要算法)保证安全。
模块九:Linux & Git
Linux
1. 列举一些你常用的Linux命令。
- 答案:
ls
, cd
, pwd
, mkdir
, rm
, cp
, mv
, cat
, tail -f
, ps -ef | grep xxx
, top
, kill -9
。
2. 如何查看一个Java进程?如何杀死它?
- 答案: 1. 查看:
ps -ef | grep java
; 2. 杀死: kill -9 [PID]
。
3. 如何实时查看日志文件?
Git
1. git pull
和 git fetch
的区别是什么?
- 答案:
git fetch
: 只拉取远程变更,不自动合并。
git pull
: 拉取并自动合并 (git fetch
+ git merge
)。
2. git rebase
和 git merge
的区别是什么?
- 答案:
git merge
: 创建一个新的“合并提交”,保留分支历史。
git rebase
: 将提交应用到目标分支最新提交之后,使提交历史变成一条直线,更整洁。
3. 如何解决代码冲突?
- 答案: 1.
git pull
后查看冲突文件; 2. 手动编辑文件,解决 <<<<<<<
, =======
, >>>>>>>
标记的内容; 3. git add [冲突文件名]
; 4. git commit
。