1. 简介
这篇文章整理了一些 Java 核心知识点中常见的面试问题及其答案。部分问题的答案可能不是显而易见的,因此通过这篇文章可以帮你厘清思路、加深理解。
2. 初级 Java 面试问题
2.1. Java 中的数据是按引用传递还是按值传递?
虽然这个问题的答案很简单,但对初学者来说可能会有些困惑。我们先明确一下两个概念:
- ✅ 按值传递(Pass by value):传递的是对象的副本。
- ❌ 按引用传递(Pass by reference):传递的是对象的引用。
在 Java 中,不管是基本类型还是对象引用,传递的都是值的副本:
- 对于基本类型:传递的是值的拷贝;
- 对于对象:传递的是引用的拷贝(但不是对象本身)。
📌 结论:Java 是严格按值传递的语言。
想深入了解?可以看看这篇文章:Java 中的参数传递机制
2.2. import 与 static import 的区别
import
用于导入某个类或整个包:
import java.util.ArrayList; // 导入特定类
import java.util.*; // 导入整个包
static import
用于导入静态成员或嵌套类:
import static java.util.Collections.EMPTY_LIST;
使用 static import
后,可以直接使用 EMPTY_LIST
,而无需加上类名前缀。
2.3. Java 中有哪些访问修饰符?它们的作用是什么?
Java 中有四种访问修饰符:
private
:仅类内部可访问;default
(包访问):仅同一包内可访问;protected
:同包或子类可访问;public
:所有地方都可访问。
⚠️ 注意:default
不是关键字,只是不写访问修饰符时的默认行为。
2.4. Java 中还有哪些其他修饰符?它们的作用是什么?
除了访问修饰符,还有以下五种常用修饰符:
static
:属于类而非实例;final
:不可变或不可继承;abstract
:用于抽象类或方法;synchronized
:用于同步控制;volatile
:保证变量的可见性。
这些修饰符不控制访问权限,而是用于控制类、方法或变量的行为。
2.5. JDK、JRE 和 JVM 的区别
名称 | 全称 | 作用 |
---|---|---|
JDK | Java Development Kit | 开发工具包,包含编译器、调试器等 |
JRE | Java Runtime Environment | 运行 Java 程序所需的最小环境 |
JVM | Java Virtual Machine | 执行字节码的虚拟机 |
📌 JDK 包含 JRE,JRE 包含 JVM。
2.6. 栈(Stack)和堆(Heap)的区别
- 栈:存储局部变量和方法调用信息,速度快,但空间有限。栈溢出时会抛出
StackOverflowError
。 - 堆:存储所有对象实例,由垃圾回收器管理。内存不足时会抛出
OutOfMemoryError
。
2.7. Comparable 与 Comparator 的区别
Comparable
:类内部实现排序逻辑,使用compareTo()
方法;Comparator
:外部定义排序规则,适用于第三方类或多种排序方式。
📌 compareTo()
和 compare()
方法最好与 equals()
保持一致。
2.8. void 类型的作用
void
表示方法不返回值;Void
是一个占位类,用于泛型场景,不能实例化。
2.9. Object 类有哪些方法?
方法 | 作用 |
---|---|
clone() |
复制对象 |
equals() |
判断相等 |
finalize() |
垃圾回收前调用 |
getClass() |
获取运行时类 |
hashCode() |
获取哈希码 |
notify() / notifyAll() |
唤醒等待线程 |
toString() |
字符串表示 |
wait() |
线程等待 |
📌 hashCode()
应与 equals()
保持一致。
2.10. 什么是 Enum?如何使用?
enum
是一种特殊类,用于定义一组常量;- 可以包含属性、方法;
- 不能被继承,但可以实现接口;
- 线程安全,常用于单例模式。
示例:
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
2.11. 什么是 JAR 文件?
JAR(Java Archive)是基于 ZIP 格式的归档文件,用于打包 Java 类文件和资源文件。支持:
- ✅ 安全签名
- ✅ 数据压缩
- ✅ 跨平台使用
- ✅ 版本控制
2.12. 什么是 NullPointerException?
NullPointerException
是最常见的运行时异常,出现在以下情况:
- 调用 null 对象的方法;
- 访问 null 对象的字段;
- 获取 null 数组长度;
- 抛出 null。
📌 不要手动捕获它,应该从源头避免。
2.13. Java 中的两种类型转换?可能抛出什么异常?如何避免?
- 向上转型(Upcasting):安全,自动进行;
- 向下转型(Downcasting):需手动转换,可能抛出
ClassCastException
。
✅ 使用 instanceof
判断避免异常:
if (obj instanceof String) {
String str = (String) obj;
}
3. 高级 Java 面试问题
3.1. 为什么 String 是不可变的?
- 存储在字符串常量池中,节省内存;
- 保证哈希值不变,适合做 Map 的 key;
- 线程安全;
- 防止敏感信息被篡改。
📌 不可变对象天生线程安全,是设计上的经典实践。
3.2. 动态绑定与静态绑定的区别
- 静态绑定:发生在编译时,适用于
private
、static
、final
方法; - 动态绑定:发生在运行时,适用于重写方法。
📌 Java 默认使用动态绑定来支持多态。
3.3. 什么是 JIT?
JIT(Just-In-Time)是 JVM 中的即时编译器,在运行时将热点代码编译为本地机器码,以提升性能。
- 编译热点代码;
- 优化 CPU 指令;
- 基于运行时数据进行优化。
📌 JIT 是 Java 高性能的关键之一。
3.4. Java 中的反射机制
反射允许程序在运行时检查或修改类的结构和行为。使用 java.lang.reflect
包。
- 可访问私有成员;
- 不需要知道类名;
- 有安全限制(Java 9+ 模块化后更严格)。
📌 反射虽强大,但影响性能,慎用。
3.5. 什么是类加载器(Classloader)?
类加载器负责将 .class
文件加载到 JVM 中。Java 提供三种默认类加载器:
- Bootstrap Classloader:加载核心类(如
java.lang.*
); - Extension Classloader:加载扩展类;
- System Classloader:加载应用类路径下的类。
📌 类加载器遵循“双亲委派模型”。
3.6. 静态类加载与动态类加载的区别
- 静态加载:使用
new
关键字; - 动态加载:使用
Class.forName()
在运行时加载类。
📌 动态加载常用于插件机制、JDBC 驱动加载等场景。
3.7. Serializable 接口的作用
实现 Serializable
接口可使类支持序列化:
- 序列化:将对象转为字节流;
- 反序列化:从字节流恢复对象。
📌 子类自动可序列化,但父类若未实现需提供无参构造函数。
3.8. Java 中有析构函数吗?
Java 没有传统意义上的析构函数,因为垃圾回收器会自动回收内存。
- 对于资源(如文件、连接):应使用
close()
方法; - Java 7+ 推荐使用
try-with-resources
; - Java 9+ 使用
Cleaner
替代finalize()
。
⚠️ finalize()
不可靠,不推荐使用。