面试题目

一、Java 基础语法 & 关键字

1. JDK、JRE 和 JVM 的区别

  • JVM(Java Virtual Machine):Java 虚拟机,负责执行字节码(.class)。提供类加载、字节码校验、内存管理(堆、方法区)、执行引擎、垃圾回收、线程调度等。是抽象的规范,具体由不同厂商实现(HotSpot、OpenJ9 等)。
  • JRE(Java Runtime Environment):运行环境,包含 JVM、核心类库(rt.jar 或 modules)、以及运行时需要的其它资源。用于运行 Java 程序。
  • JDK(Java Development Kit):开发工具包,包含 JRE + 开发工具(javacjarjavadoc、调试工具等)。用于开发 Java 程序。
    总结:JDK ⊃ JRE ⊃ JVM(JDK 包含 JRE,JRE 包含 JVM)。

2. Java 的跨平台原理是什么?

  • Java 程序先由 javac 编译成与平台无关的 字节码.class)。字节码不是机器码,而是供 JVM 执行的指令集。
  • 每个平台(Windows/Linux/macOS)有相应的 JVM 实现,JVM 把字节码翻译成该平台的机器指令(通过解释器、JIT 编译器等)。因此同一套 .class 可以在不同平台的 JVM 上运行 —— “一次编写,处处运行”(Write Once, Run Anywhere)。
  • 其它保证跨平台的要点:标准库隐藏平台差异(I/O、线程等),需避免使用与平台绑定的本地代码(JNI)。

3. Java 的基本数据类型有哪些?各自的默认值?

8 种基本类型及默认值(成员变量/数组元素;局部变量无默认值必须初始化):

  • byte:1 byte,默认值 0
  • short:2 bytes,默认值 0
  • int:4 bytes,默认值 0
  • long:8 bytes,默认值 0L
  • float:4 bytes,默认值 0.0f
  • double:8 bytes,默认值 0.0d
  • char:2 bytes(UTF-16 code unit),默认值 '\u0000'(即 0)
  • boolean:JVM 语义上用 1 bit 表示,默认值 false

另外,引用类型(对象、数组等)的默认值是 null


4. byteshortintlong 各占多少字节?

  • byte1 字节(8 位)
  • short2 字节(16 位)
  • int4 字节(32 位)
  • long8 字节(64 位)

(上述为 Java 语言规范定义,与平台无关。)


5. floatdouble 的区别?

  • 精度与存储:
    • float:32 位单精度浮点(IEEE 754),约 6~7 位有效数字。
    • double:64 位双精度浮点(IEEE 754),约 15~16 位有效数字。
  • 精度更高的 double 更常用;float 用于节省内存或与特定 API(如图形库)兼容。
  • 注意:浮点数有精度误差,不适合做精确货币计算(应使用 BigDecimal)。
  • 默认浮点字面量为 double(例如 1.2double,写成 1.2f 才是 float)。

6. char 类型占几个字节?能存汉字吗?

  • char2 字节(16 位),表示 UTF-16 的一个 code unit。
  • 能否存汉字:多数常用汉字(位于基本多文种平面 BMP)可以用单个 char 表示(例如 '你');但有些罕见汉字或 emoji 属于补充平面(Supplementary Planes),它们需要 两个 char(称为 surrogate pair) 来表示。
  • 因此,单个 char 能表示一个 UTF-16 code unit,而不是完整的 Unicode code point。处理 Unicode 字符时注意使用 int codePoint / Character 的相关 API。

7. 自动装箱(autoboxing)和拆箱(unboxing)的原理是什么?

  • 概念

    • 装箱:把基本类型自动转换成对应的包装类型(如 intInteger)。
    • 拆箱:把包装类型自动转换回基本类型(如 Integerint)。
  • 编译器行为:自动装箱/拆箱是在编译期由 Java 编译器插入对应的调用,示例:

    1
    2
    Integer a = 10;        // 编译器会转换为 Integer.valueOf(10)
    int b = a; // 编译器会转换为 a.intValue()
  • valueOf 缓存:包装类(如 Integer.valueOf(int))会对小整数(默认 -128 到 127)做缓存以重用对象,减少频繁创建对象。

  • 注意事项

    • 拆箱 null 会抛出 NullPointerException

      1
      2
      Integer x = null;
      int y = x; // NPE
    • 装箱/拆箱会有性能开销(对象创建、装箱/拆箱方法调用),在性能敏感场景尽量使用基本类型或手动优化。

    • 比较时注意:Integer a = 100; Integer b = 100; a==b 在缓存范围内可能为 true,超出范围则通常为 false


8. ==equals() 的区别?

  • ==
    • 对于基本类型:比较 (数值是否相等)。
    • 对于引用类型:比较 引用地址(是否是同一个对象)。
  • equals()
    • Object 的方法,默认实现也是比较引用(等价于 ==)。
    • 许多类(如 StringInteger、集合类等)重写了 equals(),用于比较逻辑/内容相等
  • 使用建议
    • 比较对象内容用 equals()(需检查 null),比较是否同一实例用 ==
    • equals() 配套应重写 hashCode()(见下题)。

9. hashCodeequals 的关系?

  • 合同(Contract)(重要):
    1. 如果两个对象通过 equals() 被判定为相等(a.equals(b)true),那么 a.hashCode() == b.hashCode() 必须成立。
    2. 反之不要求:hashCode 相等的对象不一定 equals() 相等(哈希冲突允许)。
  • 在哈希集合中的角色
    • 哈希表(HashMap/HashSet)先用 hashCode() 找到桶(bucket),若桶中有多个元素,再用 equals() 逐个比较确认相等或冲突。
    • 如果只重写 equals() 而不重写 hashCode() 会破坏集合行为(例如放入 HashSet 后无法正确查找)。
  • 实现要点
    • hashCode() 要尽量分散(降低冲突),并在对象不可变字段上基于相同规则计算。
    • 若对象可变,若用于哈希集合要小心:修改字段会导致 hashCode() 改变,破坏集合内部结构。

10. StringStringBufferStringBuilder 的区别?

  • String
    • 不可变(immutable),每次修改都会产生新的对象(或新内部 char/byte 数组)。
    • 线程安全(因为不可变),适合频繁读取、少量修改的场景。
  • StringBuffer
    • 可变的字符序列(内部有缓冲区 char[]/byte[]),几乎与 StringBuilder 接口相同。
    • 线程安全,其方法大多使用 synchronized,因此在多线程下可以被多个线程安全使用。
    • 相对较慢(同步开销)。
  • StringBuilder(Java 5+)
    • 可变,非线程安全(没有同步),比 StringBuffer 快。
    • 推荐在单线程或外部已同步的场景下使用。
  • 选择建议
    • 多线程需要可变字符串:StringBuffer(或外部同步)。
    • 单线程/局部构造字符串:StringBuilder
    • 常量字符串或少量拼接:String(编译器对 + 会优化为 StringBuilder)。

11. 为什么 String 是不可变的(immutable)?

原因(几条重要理由):

  1. 安全性String 经常用于关键场景(类加载器、网络地址、文件名、权限检查、数据库连接字符串等)。不可变保证在传递引用时不被恶意或意外修改。
  2. 线程安全:不可变对象固有线程安全,多个线程可共享同一 String 实例而无需同步。
  3. 性能(缓存 hashCode)String 的哈希值可缓存(hash 字段),便于作为 Map 的 key,避免重复计算。
  4. 字符串常量池:可安全地将字面量放入池中重用,不用复制或担心修改。
  5. 优化:JVM 可进行共享、常量折叠等优化(更易于实现某些编译期/运行期优化)。

12. String 常量池的实现机制?

  • 概念:编译期和运行期维护一个字符串池(String Intern Pool),用于存放字符串字面量(literal)和显式 intern() 后的字符串,以便重用相同内容的 String 实例。
  • 编译期:源代码中的字符串字面量(如 "abc")会被放到常量池(编译后的 class 文件常量池),类加载后这些字面量会放入运行时的字符串池。
  • 运行期
    • 以前(Java 6 及更早):字符串常量池在 PermGen(方法区)中。
    • Java 7 起:常量池迁移到 Java 堆(运行时常量池也在堆里),避免 PermGen 问题。
  • intern():当调用 s.intern() 时,JVM 会检查池中是否已有相同内容的字符串:
    • 若存在,返回池中的引用;
    • 若不存在,将该字符串的引用加入池并返回它。
  • 编译时优化:字符串常量的拼接(编译时常量)会在编译期合并,如 "a" + "b""ab",直接放入常量池;而运行时拼接(变量参与)则使用 StringBuilder

13. new String("abc") 创建了几个对象?

  • 通常情形
    • "abc" 字面量尚未在常量池中存在,执行 new String("abc") 会导致 两个对象 被创建:常量池中的 "abc"(一个 String)和堆中通过 new 创建的新的 String 实例(内容通常是对常量池中字符数组的复制或共享,具体实现随 Java 版本而异)。
    • 如果字面量 "abc" 已经存在于常量池中(例如之前被加载过),那么 new String("abc") 只会创建 一个堆对象(new 的那个 String)。
  • 注意:自 Java 7/9 后 String 内部实现改变(压缩字符串、byte[] 存储等),但逻辑上上述结论成立:通常 1 或 2 个对象,取决于常量池中是否已存在该字面量。

14. final 关键字的作用?

  • 用于类(final class):类不可被继承(如 String)。
  • 用于方法(final 方法):方法不能被子类重写(override),用于确保行为不可变。
  • 用于变量(final 字段/局部变量)
    • 对基本类型:赋值后值不可改变(常量)。
    • 对引用类型:引用不可改变(不能指向另一个对象),但所指向对象的内部状态仍可变(除非对象本身不可变)。
    • static final 常用来定义常量(编译期常量)。
  • 用于参数(方法形参可以声明为 final):代表方法内不能修改该参数引用/值。
  • 其它用途:在多线程中,final 字段的写-构造过程被 JMM(Java 内存模型)处理,确保构造完成后其他线程可见(安全发布方面有好处)。

15. static 关键字的作用?

  • 用于声明类级别成员(字段、方法、初始化块、嵌套类),不依赖实例。
  • static 变量:类变量,所有实例共享一份。内存中仅有一份副本。
  • static 方法:类方法,可通过 ClassName.method() 调用;不能直接访问非静态成员(因无 this)。
  • static 代码块:类加载时执行一次(用于静态初始化)。
  • static 嵌套类:可以声明为静态的内部类(静态嵌套类),没有外部实例引用。

16. static 修饰变量、方法、代码块分别意味着什么?

  • static 变量(类变量)
    • 随类加载而创建,所有对象共享同一份数据。
    • 可通过 ClassName.fieldinstance.field(不推荐)访问。
  • static 方法
    • 属于类,调用时无需实例。
    • 不能使用 this、不能直接访问非静态成员。
    • 可作为工具方法(如 Math.abs())。
  • static 代码块
    • 在类加载阶段执行一次,用于复杂静态初始化(比如初始化静态常量、加载本地库等)。
    • 执行顺序:静态块按定义顺序执行,类加载时运行(在实例化之前)。

17. staticfinal 能一起用吗?

  • static final 常用于定义类常量(尤其是基本类型和 String),例如:

    1
    2
    public static final int MAX = 100;
    public static final String NAME = "abc";
  • 区别

    • 如果是编译期常量(static final 基本类型或 String 且在编译时可以确定),编译器会将其内联到使用处(被引用的类编译后看到的是常量值),注意跨模块修改可能导致需要重新编译引用方。
    • 如果是 static final 引用对象且不是编译期常量,则引用本身不可变,但对象内容可能可变。

18. static 内部类和非静态内部类的区别?

  • 静态内部类(static nested class)
    • 相当于外部类的一个静态成员。
    • 没有对外部类实例的隐式引用(不能直接访问外部类的非静态成员)。
    • 可以像普通类那样实例化:Outer.StaticInner inner = new Outer.StaticInner();
  • 非静态内部类(inner class)
    • 每个实例隐式持有一个外部类实例引用(Outer.this),可以直接访问外部类的所有成员(包括私有成员)。
    • 创建方式:Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();
    • 占用外部类对象的内存引用,可能导致内存泄露(如果长期持有内部类实例导致外部类不能被回收)。
  • 选择原则:如果内部类不需要访问外部实例成员,优先使用 static 嵌套类,避免额外引用。

19. Java 中的 thissuper 的区别?

  • this
    • 引用当前对象的引用。
    • 用于访问当前类的实例变量、调用当前类的其他构造器(this(...))、或传递当前对象引用。
  • super
    • 引用当前对象的父类部分。
    • 用于访问父类被覆盖的方法(super.method())、父类字段(若有同名字段)、以及在子类构造器第一行调用父类构造器(super(...))。
  • 注意
    • this()super() 必须在构造器的第一行(两者不能同时出现)。
    • super 不能用于访问父类的 private 成员(编译期限制)。

20. Java 中构造方法能否被重写?

  • 不能。重写(override)适用于实例方法,构造方法不是继承的成员,子类不能重写父类的构造器。
  • 可以重载(overload):在同一类中同名构造器有不同参数列表属于重载。
  • 子类构造器可通过 super(...) 显式调用父类构造器来完成父类初始化。

21. 接口和抽象类的区别?

  • 接口(interface)
    • 早期(Java 7 之前):只包含抽象方法(默认是 public abstract)和 public static final 常量。
    • Java 8+:可以包含 default 方法与 static 方法(可以有部分实现);Java 9+ 允许 private 方法。
    • 支持多继承(一个类可以实现多个接口)。
    • 没有实例字段(除 static final 常量外)。
  • 抽象类(abstract class)
    • 可以有实例字段(非静态成员变量)、已有实现的方法(具体方法)、构造器。
    • 适合表示一类有共同行为并共享状态的类层次。
    • 类只能单继承(只能继承一个抽象类)。
  • 选择建议
    • 如果需要多继承行为、只定义方法契约且不需要状态,使用接口。
    • 如果需要提供共有实现和状态,使用抽象类。

22. 接口中可以有 default 方法和 static 方法吗?

  • 可以(Java 8 起)
    • default 方法:为实现类提供默认实现,避免破坏已有实现(接口演化)。实现类可以覆盖(override)。
    • static 方法:属于接口自身,可以通过 InterfaceName.method() 调用,不能通过实例调用。
  • Java 9 及以后还可有 private 方法,供接口内部复用实现逻辑。

23. Java 8 接口新增了什么?

  • Java 8 在接口中新增了 default 方法static 方法,允许接口提供带实现的方法,从而便于接口的演化(向后兼容)。这也是 Java 8 引入函数式编程支持的基础之一(允许接口作为函数式接口)。

24. Java 8 有什么新特性,并详细介绍(重点)


一、Java 8 新特性深入解析

好的,我来帮你把 Java 8 的六大核心特性(Lambda、函数式接口、Stream API、方法引用、java.time API、Optional) 进行 完整整合,从概念、示例、底层原理、实现机制、特点和优势做一个统一、连贯的解析。


Java 8 六大核心特性整合解析

1. Lambda 表达式

概念

  • 匿名函数,允许把行为作为参数传递。
  • 简化匿名内部类写法,实现函数式编程。

示例

1
2
List<String> list = Arrays.asList("a", "bb", "ccc");
Collections.sort(list, (s1, s2) -> s1.length() - s2.length());

底层原理

  • 编译器生成静态/实例方法 + invokedynamic 指令。
  • JVM 调用 LambdaMetafactory 动态生成函数对象,实现 函数式接口
  • 捕获外部变量通过闭包机制存储(必须是 effectively final)。

特点

  • 语法简洁
  • 可作为参数传递行为
  • 性能高于匿名内部类(减少对象创建)

2. 函数式接口

概念

  • 仅有一个抽象方法的接口,用作 Lambda 表达式的目标类型。
  • 可用 @FunctionalInterface 标识。

示例

1
2
3
4
5
6
7
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}

Converter<String, Integer> c = Integer::valueOf;
System.out.println(c.convert("123")); // 123

底层原理

  • Lambda 表达式编译时生成实现函数式接口的函数对象。
  • 捕获变量通过闭包对象保存。

特点

  • 简化匿名类
  • 支持函数式编程
  • 可与 Stream / Optional 等结合

3. Stream API

概念

  • 对集合进行声明式操作(过滤、映射、归约)。
  • 支持 惰性求值并行处理

示例

1
2
3
4
5
6
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> filtered = names.stream()
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(filtered); // [ALICE, CHARLIE]

底层原理

  • Stream 是流水线对象,中间操作返回新的 Stream,终端操作触发计算。
  • 串行流:顺序迭代器处理
  • 并行流:ForkJoinPool 分块处理

特点

  • 声明式、链式操作
  • 支持并行
  • 可与 Lambda / 方法引用结合

4. 方法引用

概念

  • Lambda 表达式的简化写法,引用现有方法。
  • 类型:
    1. 静态方法引用:ClassName::staticMethod
    2. 实例方法引用:instance::method
    3. 构造器引用:ClassName::new

示例

1
2
3
List<String> names = Arrays.asList("a", "bb", "ccc");
names.forEach(System.out::println); // 实例方法引用
Supplier<List<String>> listSupplier = ArrayList::new; // 构造器引用

底层原理

  • 编译器转成 Lambda 表达式 + invokedynamic。
  • JVM 生成实现函数式接口的函数对象,内部持有方法引用。

特点

  • 简洁直观
  • 可减少 Lambda 代码
  • 与 Stream / Optional 配合使用

5. java.time API

概念

  • 替代 Date / Calendar,不可变、线程安全。
  • 核心类:
    • LocalDate / LocalTime / LocalDateTime(无时区)
    • ZonedDateTime(带时区)
    • Duration / Period(时间段)

示例

1
2
3
4
5
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Singapore"));
System.out.println(tomorrow);
System.out.println(zdt);

底层原理

  • 内部字段 final 保存值,不可变。
  • 工厂方法创建对象,链式操作返回新对象。
  • 使用 enum + 整型/字节优化存储(如 LocalDate 年月日用 int)。

特点

  • 不可变,线程安全
  • 链式操作,易组合
  • 支持各种历法和时区计算

6. Optional

概念

  • 容器对象,防止 NullPointerException
  • 可以包含值或为空(empty)。

示例

1
2
3
4
5
6
Optional<String> opt1 = Optional.of("Hello");
Optional<String> opt2 = Optional.ofNullable(null);

System.out.println(opt1.isPresent()); // true
System.out.println(opt2.orElse("Default")); // Default
opt1.map(String::toUpperCase).ifPresent(System.out::println); // HELLO

底层原理

  • 内部 value 字段存储非空值,空值使用单例 EMPTY
  • map / flatMap / filter 返回新的 Optional,对象不可变。
  • 与 Lambda / 函数式接口结合实现链式安全操作。

特点

  • 避免显式 null 判断
  • 支持链式调用
  • 可与 Stream / Lambda 配合

Java 8 六大核心特性底层对比表

特性 底层实现 核心原理 优势
Lambda invokedynamic + LambdaMetafactory 动态生成函数对象 简洁、性能高
函数式接口 单抽象方法接口 捕获变量通过闭包存储 简化匿名类,函数式编程
Stream API 流水线 + 延迟求值 中间操作惰性,终端触发 声明式、可并行
方法引用 Lambda 简化语法 + invokedynamic 内部持有方法引用 简洁直观,减少代码
java.time 不可变对象 + 工厂方法 final字段保存值,链式返回新对象 线程安全,可组合
Optional 包装对象 + 单例 EMPTY 不可变容器,函数式链式调用 避免 NPE,安全链式操作

1. Lambda 表达式

语法

1
2
(parameters) -> expression
(parameters) -> { statements; }

示例:排序

1
2
3
4
5
6
7
8
9
10
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 传统匿名类写法
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
// Lambda 写法
Collections.sort(names, (s1, s2) -> s1.length() - s2.length());

图示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
编译器把 Lambda 转成匿名类或 invokedynamic 机制
+----------------+
| Lambda 表达式 |
+----------------+
|
v
+----------------+
| JVM runtime |
| invokedynamic |
+----------------+
|
v
+----------------+
| Function Object|
+----------------+
  • 捕获外部变量:必须是 effectively final,底层通过匿名类的构造器保存引用或值。

2. Stream API

特点

  1. 声明式:关注“做什么”,而非“怎么做”。
  2. 惰性求值:中间操作不会立即执行,终端操作触发。
  3. 可并行:使用 .parallelStream() 自动利用多核 CPU。

示例:数据处理

1
2
3
4
5
6
7
List<String> words = Arrays.asList("Java","Python","C++","Go");
List<String> filtered = words.stream()
.filter(s -> s.length() > 2)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
System.out.println(filtered); // [C++, JAVA, PYTHON]

图示

1
2
3
4
List -> Stream -> filter -> map -> sorted -> collect
| | | | |
v v v v v
数据流 中间操作 中间操作 中间操作 终端操作

3. 方法引用

类型

  1. 静态方法Class::staticMethod
  2. 实例方法instance::method
  3. 构造器Class::new

示例

1
2
3
List<String> names = Arrays.asList("a", "bb", "ccc");
names.forEach(System.out::println); // 实例方法引用
Supplier<List<String>> listSupplier = ArrayList::new; // 构造器引用

4. java.time API

示例

1
2
3
4
5
6
LocalDate date = LocalDate.of(2025, 9, 10);
LocalDate tomorrow = date.plusDays(1);
System.out.println(tomorrow); // 2025-09-11

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Singapore"));
System.out.println(zdt);

图示

1
2
3
4
5
6
LocalDate/Time (不可变)
|-- plusDays()
|-- minusMonths()
|-- withDayOfMonth()
v
新的 LocalDate/Time 对象
  • 线程安全:无需同步即可共享对象。

5. Optional

示例

1
2
3
Optional<String> opt = Optional.ofNullable(null);
String result = opt.orElse("默认值");
System.out.println(result); // 默认值

图示

1
2
3
4
5
6
7
8
Optional.ofNullable(value)
|
v
+-----------------+
| value != null ? |
| contains value |
| else empty() |
+-----------------+

二、synchronized 底层原理深入解析

1. JVM 锁的类型

锁类型 特点 性能
偏向锁 (Biased Lock) 无竞争时偏向第一个线程,轻量
轻量级锁 (Lightweight) 竞争少时使用 CAS 升级锁
重量级锁 (Monitor) 高竞争时使用 OS mutex,阻塞线程

2. synchronized 对象头结构

  • 每个对象在 JVM 内存中都有 对象头(Mark Word),存储锁信息、哈希码、GC 标记等。
1
2
3
4
对象头 Mark Word (32/64bit)
+----------------+----------------+----------------+
| HashCode | GC info | Lock info |
+----------------+----------------+----------------+
  • 锁标记位
    • 00:无锁
    • 01:偏向锁
    • 10:轻量级锁
    • 11:重量级锁

3. synchronized 执行流程

a) 偏向锁(无竞争)

1
线程获取锁 -> 在对象头打上线程ID -> 执行 -> 释放锁 -> 保持偏向状态

b) 轻量级锁(CAS竞争)

1
2
线程尝试CAS抢锁 -> 成功:持有锁 -> 执行 -> 释放
|-> 失败:升级为重量级锁

c) 重量级锁(阻塞)

1
线程无法获取锁 -> 阻塞(OS等待队列) -> 被唤醒 -> 获取锁 -> 执行 -> 释放锁

图示

1
2
3
4
5
6
7
8
9
+------------------+
| synchronized() |
+------------------+
|
JVM对象头Mark Word
|
+------------------------+
| 偏向锁 -> 轻量级锁 -> 重量级锁
+------------------------+

4. synchronized 方法示例

1
2
3
4
5
6
7
8
9
10
11
class Counter {
private int count = 0;

public synchronized void increment() {
count++;
}

public int getCount() {
return count;
}
}
  • 锁对象:实例方法锁住 this,静态方法锁住类对象 ClassName.class
  • 效果:同一时间只有一个线程能进入 increment(),保证 count++ 操作的原子性。

5. JVM 优化

  • 锁消除:编译器或 JIT 可检测无竞争情况,消除同步锁。
  • 锁粗化:把多次连续的小范围锁合并,减少加锁次数。
  • 偏向锁 / 轻量级锁 / 重量级锁升级:动态适应竞争情况,兼顾性能与正确性。

如果你愿意,我可以帮你把 Java 8 新特性synchronized 底层原理 做一张 图解全流程总结图,把 Lambda、Stream、锁状态、对象头等内容融合成一张直观的图,方便记忆和面试答题。

你希望我做这张图吗?25. 多态的实现机制是什么?

  • 概念:同一操作作用于不同对象时表现出不同的行为(主要表现为方法的动态绑定)。
  • 实现机制
    • 编译时:根据引用类型检查方法签名(静态类型检查)。
    • 运行时:实际调用的方法根据对象的实际类型(运行时类型)决定;即 动态绑定(dynamic dispatch)
    • JVM 通常通过 虚方法表(vtable)/方法查找机制 实现。调用一个非 static、非 private、非 final 的方法时,会在运行时查找实际类的实现并调用。
  • 结果:子类可以覆盖父类方法,调用者使用父类引用指向子类对象时,调用的是子类的覆盖方法(运行时决定)。
  • 注意staticprivatefinal 方法不会被动态绑定(是静态绑定)。

26. 方法重载(overload)和方法重写(override)的区别?

  • 方法重载(Overloading)

    • 同一类中方法名相同、参数列表不同(参数类型/个数/顺序),返回类型可以不同。
    • 编译时决定(重载解析在编译期完成),与继承关系无关。
  • 方法重写(Overriding)

    • 子类定义与父类相同方法签名(方法名 + 参数类型相同)的实现,目的是改变/扩展父类行为。
    • 运行时动态绑定,必须满足访问权限不能更严格,抛出的受检异常不能超过父类版本等规则。
  • 示例

    1
    2
    3
    4
    5
    6
    // overload
    void f(int x) {}
    void f(String s) {}
    // override
    class A { void m() {} }
    class B extends A { @Override void m() {} }

27. Java 支持多继承吗?如何实现类似效果?

  • 类的多继承:Java 不支持类的多继承(不能继承多个类),以避免菱形继承问题(diamond problem)。
  • 实现类似效果的方法
    • 接口多实现:一个类可以实现多个接口(Java 8 的 default 方法也带来类似多继承方法实现的可能,但有冲突解决规则)。
    • 组合/委托(composition/delegation):在类中持有其它类的实例并把调用委托给它们(优于继承的面向对象设计原则)。
  • 接口冲突解决:若多个接口提供相同默认方法,类必须重写该方法并明确调用哪个接口的默认实现(InterfaceName.super.method())。

28. Java 的四种访问修饰符?

  • public:对所有类可见(任何包)。
  • protected:对同包类和子类可见(即同包或子类可以访问)。
  • 默认(包私有,package-private)(不写修饰符):对同包类可见,包外不可见。
  • private:仅在本类内可见,包外/子类不可访问(子类无法直接访问父类 private 成员)。
  • 注意:对类(顶层类)只能使用 public 或默认(包私有),不能声明为 private/protected

29. transient 关键字的作用?

  • 用于标记字段在 Java 序列化(Serializable)过程中不被序列化
  • 被标记为 transient 的字段在序列化后不会写入序列化流,反序列化时这些字段会以默认值恢复(基本类型 0,引用类型 null)。
  • 常用于敏感信息(密码)、不需要持久化的缓存字段、或可重建的状态字段。
  • 注意:static 字段本身也不会被序列化(因为是类级别,不属于实例状态)。

30. volatile 关键字的作用?

  • 可见性:保证对 volatile 变量的写入对其它线程立即可见(读取总是从主内存而不是线程缓存读取)。
  • 禁止指令重排序(部分):读/写 volatile 存在的内存屏障能保证一定的有序性(写 volatile 发生在后续读的可见性上,更多细节参考 JMM)。
  • 不保证原子性:对单次读/写操作是原子的(对 long/double 在 Java 5 后也保证原子),但非原子操作(如 i++)不是原子的。
  • 典型用途
    • 状态标志(如 volatile boolean running)。
    • 用于实现双重检查锁定(DCL)单例中的 instance(在 Java 5+ 环境下有效)。
  • 与 synchronized 比较
    • volatile 轻量,只保证可见性与部分有序性,不保证互斥;适用于简单状态通信。
    • synchronized 提供互斥和可见性保证(更重),并可配合 wait/notify

31. synchronized 的作用及底层原理?

作用

  • 互斥(排它):保证同一时间只有一个线程可以执行被 synchronized 修饰的代码块或方法(针对同一把锁)。
  • 可见性:进入/退出同步块会建立 happens-before 关系,确保锁释放前的写对随后获取该锁的线程可见。
  • 用途:保护临界区、确保多个线程对共享可变状态的安全访问。

使用方式

  • 方法级别
    • synchronized void m() { ... }:等价于 synchronized(this)(实例方法)或 synchronized (ClassName.class)(静态方法)。
  • 代码块级别
    • synchronized(this) { ... }synchronized(lockObj) { ... } 更灵活,能减小锁的粒度。

底层原理(HotSpot 实现概要)

  • JVM 使用对象头(object header)中的 mark word 和关联数据结构维护锁状态。
  • 锁优化策略(为提升性能,HotSpot 引入若干优化):
    1. 偏向锁(Biased Locking):在没有竞争的情况下,锁会偏向于第一次获得它的线程,重复获取无需 CAS,减少开销。
    2. 轻量级锁(Lightweight Locking):使用 CAS 操作在栈上记录加锁记录,避免进入重量级监视器(monitor)。
    3. 重量级锁(Monitor/Mutex):当竞争激烈或 CAS 失败时,升级为重量级锁,使用操作系统互斥量(可能涉及线程阻塞/唤醒)。
  • monitorenter / monitorexit 是字节码指令(由编译器/字节码生成器生成)。
  • JIT 编译器可进行锁消除、锁粗化、锁优化等(当能证明无并发访问或已外部同步时)。

wait/notify/notifyAll

  • Object.wait()notify()notifyAll() 必须在持有对象监视器(即在 synchronized 块内)时调用,用于线程间协作(条件等待/通知)。
  • wait() 会释放锁并进入等待队列;notify() 唤醒等待队列中的一个线程(被唤醒线程在重新获得锁后继续)。

注意与陷阱

  • 锁粒度:避免用过大锁(如 synchronized 在方法头部锁住大量操作),谨慎使用 String 或装箱对象作为锁(可能会导致多个实例共用同一锁或锁被外部持有)。
  • 死锁:多线程锁顺序不当可能死锁;设计时谨防。
  • 性能:在高并发下可考虑使用 java.util.concurrent 包(ReentrantLockConcurrentHashMapAtomicXxx)等更细粒度、高性能的并发工具。


二、面向对象编程(OOP)

  1. 面向对象的三大特性是什么?
  2. 封装的作用是什么?
  3. 多态的优点是什么?
  4. 重写方法时返回值能否不同?
  5. 构造函数能否被继承?
  6. 构造函数能否 private?
  7. 单例模式的几种实现方式?
  8. 饿汉式和懒汉式单例的区别?
  9. 为什么要使用内部类?
  10. 成员内部类、局部内部类、静态内部类的区别?
  11. Java 中对象的创建方式有哪些?
  12. 对象之间的浅拷贝和深拷贝的区别?
  13. clone() 方法的原理?
  14. 为什么 Java 不支持多继承?
  15. Java 是值传递还是引用传递?
  16. 方法参数传递时是如何处理对象的?
  17. 封装性体现在哪些方面?
  18. 为什么需要继承?
  19. 重写 Object 类的 toString 方法的意义?
  20. 重写 Object 类的 equals 方法时需要注意什么?

三、异常处理

  1. Java 的异常体系结构?
  2. Checked Exception 和 Unchecked Exception 的区别?
  3. throw 和 throws 的区别?
  4. try-catch-finally 的执行顺序?
  5. finally 中的 return 会覆盖 try 中的 return 吗?
  6. try-with-resources 的作用?
  7. 自定义异常类如何实现?
  8. Error 和 Exception 的区别?
  9. NullPointerException 常见场景有哪些?
  10. 运行时异常需要捕获吗?为什么?

四、集合框架(Collections)

  1. Collection 和 Collections 的区别?
  2. List、Set、Map 的区别?
  3. ArrayList 和 LinkedList 的区别?
  4. HashMap 的底层实现?
  5. HashMap 1.7 和 1.8 的区别?
  6. HashMap 如何解决哈希冲突?
  7. HashSet 的底层实现?
  8. ConcurrentHashMap 的底层实现?
  9. Hashtable 和 HashMap 的区别?
  10. TreeMap 和 HashMap 的区别?
  11. WeakHashMap 的特点?
  12. CopyOnWriteArrayList 的应用场景?
  13. LinkedHashMap 的底层原理?
  14. Map 的 key 是否可以为 null?
  15. ArrayList 扩容机制?
  16. Vector 和 ArrayList 的区别?
  17. PriorityQueue 的底层实现?
  18. BlockingQueue 的几种实现类?
  19. HashMap 死循环问题出现在哪个版本?
  20. fail-fast 和 fail-safe 的区别?

五、并发编程(JUC)

  1. Java 中的线程生命周期?
  2. Runnable 和 Callable 的区别?
  3. ThreadPoolExecutor 的参数有哪些?
  4. 线程池的拒绝策略有哪些?
  5. 创建线程的四种方式?
  6. synchronized 的底层实现原理?
  7. synchronized 和 ReentrantLock 的区别?
  8. 公平锁和非公平锁的区别?
  9. AQS 的原理?
  10. CountDownLatch 的应用场景?
  11. CyclicBarrier 的应用场景?
  12. Semaphore 的应用场景?
  13. Exchanger 的应用场景?
  14. volatile 能保证原子性吗?
  15. CAS 的原理?
  16. ABA 问题是什么?怎么解决?
  17. ThreadLocal 的作用及原理?
  18. ThreadLocal 内存泄漏的原因?
  19. JUC 中的原子类有哪些?
  20. 乐观锁和悲观锁的区别?

六、JVM & 内存模型

  1. JVM 内存结构?
  2. 堆和栈的区别?
  3. 堆内存的分代模型?
  4. 新生代、老年代、永久代的区别?
  5. 元空间和永久代的区别?
  6. 对象在堆中的分配过程?
  7. 对象什么时候进入老年代?
  8. JVM 的垃圾回收算法?
  9. 垃圾收集器有哪些?
  10. CMS 和 G1 的区别?
  11. Minor GC 和 Full GC 的区别?
  12. 什么是 Stop The World?
  13. JVM 常见的调优参数?
  14. 类加载的双亲委派机制?
  15. 双亲委派的好处?
  16. 类加载器的种类?
  17. OOM 的常见类型?
  18. 内存泄漏和内存溢出的区别?
  19. finalize() 方法的作用?
  20. Java 内存模型(JMM)的核心内容?

七、泛型、注解、反射

  1. 什么是泛型?
  2. 泛型的类型擦除机制?
  3. 泛型通配符 ? extends? super 的区别?
  4. 注解的作用是什么?
  5. 元注解有哪些?
  6. 自定义注解如何实现?
  7. 反射的作用?
  8. 反射的性能问题?
  9. 反射能否访问私有字段?
  10. 动态代理的两种实现方式?
  11. JDK 动态代理和 CGLIB 的区别?
  12. 反射如何创建对象?
  13. Class.forName 和 ClassLoader.loadClass 的区别?
  14. 注解和反射结合能实现哪些功能?
  15. 注解处理器(APT)的作用?

八、Java 8+ 新特性

  1. Lambda 表达式的作用?
  2. 函数式接口有哪些?
  3. Stream 流的常见操作?
  4. Optional 的作用?
  5. CompletableFuture 的作用?
  6. Java 8 接口的默认方法和静态方法?
  7. forEach 和传统 for 的区别?
  8. parallelStream 的原理?
  9. Java 9 模块化系统(Jigsaw)是什么?
  10. Java 14 的 switch 表达式增强?
  11. Java 16 的 record 特性?
  12. Java 17 的 sealed class 特性?
  13. var 关键字是什么?
  14. ZGC 的特性?
  15. Project Loom 的虚拟线程是什么?

九、IO

好 — 我把范围 大幅扩展并细化,把 Socket / TCP / UDP / TLS / WebSocket / 内核调优 / 实战题 / 编码题 都加进来了。现在给你一个160 道题目清单(按主题分组),覆盖面更广、更细致,便于你当面试题库或复习大纲使用。

Java IO & Socket 深度面试题(160题)


一、Java IO 基础与流(1–20)

  1. Java IO 的总体体系结构是什么?
  2. InputStream / OutputStream 的常见子类有哪些?
  3. Reader / Writer 的常见子类有哪些?
  4. 字节流与字符流的本质区别和使用场景?
  5. 为什么要有缓冲流(BufferedInputStream / BufferedReader)?
  6. flush() 与 close() 的区别与细节(含异常处理)?
  7. try-with-resources 的工作原理(AutoCloseable、suppressed exceptions)?
  8. 装饰器模式在 Java IO 中如何体现?举例链式包装。
  9. File 类的能力与限制(能否读写数据、元数据操作)?
  10. RandomAccessFile 的用途、指针机制与并发注意点?
  11. FileInputStream 与 FileReader 有什么差别?何时用哪个?
  12. 常见的文件读写拷贝实现方式(read/write、buffered、NIO transferTo)性能对比。
  13. 如何安全地读写文本并处理字符编码(InputStreamReader/OutputStreamWriter)?
  14. 字符编码问题常见坑(UTF-8 与 GBK 混用、BOM、截断)如何避免?
  15. 文件追加(append)实现方式与原子性问题。
  16. 如何判断并处理文件是否存在、权限、是否被占用?
  17. File.mkdirs() 与 mkdir() 的区别与返回值含义。
  18. 临时文件(File.createTempFile)与删除策略。
  19. 文件的读写锁与并发访问策略(何时需要外部锁)。
  20. 流关闭异常处理的最佳实践。

二、Java IO 设计与模式(21–40)

  1. InputStream/OutputStream 的装饰器链常见组合(Buffered -> GZIP -> Cipher 等)。
  2. PushbackInputStream、SequenceInputStream 的作用与应用场景。
  3. PipedInputStream / PipedOutputStream(管道流)的使用与线程注意点。
  4. FilterInputStream/FilterOutputStream 的设计与扩展。
  5. IO 与异常处理:IOException 的常见子类与处理策略。
  6. 流复制的常见实现模板(模板方法式代码)。
  7. NIO 引入前的 IO 局限性(可扩展性、线程模型)。
  8. 如何实现一个带超时的读操作(Socket/Channel)?
  9. 流式处理与内存友好型处理(流式处理大文件)实践。
  10. Base64 编解码在流中的高效集成方法。
  11. 加密/解密流(CipherInputStream/CipherOutputStream)如何正确关闭?
  12. GZIPInputStream/GZIPOutputStream 的压缩流使用注意事项。
  13. ObjectInputStream/ObjectOutputStream 的工作机制(类元数据、句柄表)。
  14. 如何实现跨语言的序列化兼容(JSON/Protobuf/Avro)?
  15. 实现自定义 InputStream 子类时需要注意什么(read 方法语义)?
  16. 设计用于日志写入的高吞吐 IO 模式(异步批量写)。
  17. 流复制时如何统计速率与进度(带进度回调)?
  18. 如何安全处理二进制文件(流边界、magic header)?
  19. 大对象/大数组写入流时的内存优化策略(分块、流化)。
  20. 如何实现可重入/可恢复的断点续传文件写入?

三、文件系统、锁与操作(41–60)

  1. Java 中文件锁 FileLock 的类型(共享/独占)及实现原理。
  2. FileLock 的局限性(跨 JVM、跨 OS 行为差异)。
  3. 文件描述符泄露的常见原因与定位方法。
  4. 文件句柄上限(ulimit)对 Java 服务的影响与排查。
  5. 硬链接与软链接在 Java 中如何区分与操作?
  6. MappedByteBuffer(内存映射文件)的优劣与风险(内存回收、文件锁)。
  7. 大文件分片读取与并发合并策略。
  8. 如何高效统计大日志文件中某条件的行数(分块 + 并行)?
  9. 文件系统缓存(PageCache)对读写性能的影响机制。
  10. fsync / FileDescriptor.sync 在持久化保障上的作用。
  11. 文件顺序写与随机写的性能差异与优化建议。
  12. 磁盘类型(SSD vs HDD)对 IO 策略的影响。
  13. 原子重命名(renameTo/Files.move)的跨平台差异。
  14. 文件监控(WatchService)的实现限制与替代方案。
  15. 处理日志切割(rotation)时的文件句柄管理策略。
  16. 如何实现零停机部署中对文件的平滑迁移?
  17. 软删除(标记删除)与物理删除的 IO 考量。
  18. 备份/快照策略对 IO 的影响(冷备 vs 热备)。
  19. 大文件校验(MD5/SHA)在流式处理中的实现。
  20. 文件系统一致性问题(写入后立即读取到不同步)如何诊断。

四、序列化与反序列化(61–75)

  1. Java 原生序列化(Serializable)的机制和对象写入格式。
  2. serialVersionUID 的作用、自动生成与兼容性策略。
  3. transient 字段、static 字段在序列化中的处理。
  4. Externalizable 与 Serializable 的区别与使用场景。
  5. Java 序列化的安全风险(反序列化漏洞)与防护措施。
  6. 高性能二进制序列化方案对比:Kryo、Protostuff、Protobuf、Avro。
  7. JSON 和二进制序列化的权衡(可读性 vs 性能/大小)。
  8. 如何实现可演化的序列化协议(向前/向后兼容)?
  9. 对象图序列化时循环引用的处理(句柄机制)。
  10. 对象序列化性能调优要点(缓冲、对象重用)。
  11. 在分布式系统中如何管理序列化策略(跨服务版本)?
  12. 自定义序列化(writeObject/readObject)常见陷阱。
  13. 序列化时如何处理类加载器问题?
  14. 大对象序列化时的内存与 GC 风险如何降低?
  15. 使用序列化作为缓存(Redis/Memcached)时的注意事项。

五、NIO 深入:Buffer / Channel / Selector(76–100)

  1. NIO 三大核心(Buffer、Channel、Selector)各自职责是什么?
  2. ByteBuffer 的 position / limit / capacity 三指针语义详解。
  3. flip(), clear(), rewind(), compact() 各自什么时候用?
  4. DirectByteBuffer 与 HeapByteBuffer 的底层差异与性能影响。
  5. ByteBuffer 的切片(slice)与只读视图(asReadOnlyBuffer)。
  6. Scatter/Gather IO(分散读取/聚集写入)的使用场景与实现。
  7. FileChannel 的 position、size、truncate 等方法详解。
  8. MappedByteBuffer(内存映射)在 NIO 中如何创建与释放?
  9. Channel 与传统 Stream 的区别(阻塞/非阻塞、文件描述符共享)。
  10. Selector 的工作流程:注册、选择、取消、keys、selectedKeys。
  11. Selector 的底层实现依赖(select/poll/epoll/kqueue)及其影响。
  12. 非阻塞 Channel 的 read/write 返回值语义(-1、0、>0)。
  13. NIO 中的粘包/拆包问题与常见解决策略(定长/分隔/长度前置)。
  14. 如何在 NIO 中实现超时断开和心跳检测?
  15. Pipe(管道)在 NIO 中的用途与限制。
  16. 多 Selector / 多 Reactor 的线程模型设计要点。
  17. ByteBuffer 内存可见性与多线程访问问题(不是线程安全)。
  18. 避免 NIO 频繁创建 DirectByteBuffer 的垃圾和内存泄露策略。
  19. 使用 Selector 时的遍历与删除 selectedKeys 的正确姿势。
  20. NIO 读写循环的高效实现模板。
  21. Channel.transferTo/transferFrom 的零拷贝含义与局限。
  22. NIO 与 FileChannel 实现文件间高效复制的流程。
  23. 使用 NIO 实现高并发服务器时的常见瓶颈。
  24. NIO 在 Windows 与 Linux 上的行为差异(可伸缩性影响)。
  25. 实战题:实现一个使用 NIO 的简单 echo 服务器(思路要点)。

六、Socket / TCP / UDP / WebSocket(101–140)

  1. Socket 的基本概念:端点、三元组/四元组(IP:port + peer)。
  2. Java 中 Socket、ServerSocket、DatagramSocket 的主要 API 区别。
  3. TCP 与 UDP 的核心差异(可靠性、有序性、连接性)。
  4. TCP 三次握手(SYN、SYN-ACK、ACK)与四次挥手流程详解。
  5. TIME_WAIT、CLOSE_WAIT、FIN_WAIT1/2 等 TCP 状态含义与产生原因。
  6. 半开连接(half-open)是什么,如何检测与恢复?
  7. TCP 的流量控制(窗口)与拥塞控制(慢启动、拥塞避免、快重传、快恢复)基础。
  8. Nagle 算法(TCP_NODELAY)的原理和在延迟场景下的影响。
  9. TCP 延迟确认(delayed ACK)对交互型应用的影响。
  10. Socket 选项 SO_TIMEOUT、SO_KEEPALIVE、SO_REUSEADDR、SO_REUSEPORT、SO_LINGER 含义与使用场景。
  11. backlog 参数(ServerSocket 构造或 listen)与 accept 队列(syn, accept 队列)区别。
  12. ephemeral port(短暂端口)与端口耗尽问题及解决办法。
  13. SYN flood 攻击的原理和防护(SYN cookies、firewall)。
  14. TCP 快速打开(TCP Fast Open)是什么,有何优劣?(简述)
  15. MTU、MSS 与 IP 分片对传输的影响与诊断方法。
  16. UDP 的组播(Multicast)与广播(Broadcast)机制与 Java 支持(MulticastSocket)。
  17. UDP 丢包、乱序、包大小限制(最佳实践)。
  18. UDP 穿透 NAT(STUN/ICE)的基本原理。
  19. 如何在 Java 中实现高性能 UDP 服务器?(NIO + DatagramChannel)
  20. WebSocket 协议基础(握手、帧格式、ping/pong、close)。
  21. Java 实现 WebSocket 的常见库(javax.websocket、Netty websocket、Undertow)。
  22. TLS over TCP(HTTPS)的握手流程要点(证书验证、对称密钥协商)。
  23. 使用 SSLSocket / SSLServerSocket 和 SSLEngine 的差别及适用场景。
  24. SSL/TLS 握手的重用(session resumption)与性能优化。
  25. 中间人攻击(MITM)与证书链、CA、信任根的角色。
  26. 如何在 Socket 程序中实现心跳、超时与断线重连?
  27. TCP Keepalive 与应用层心跳的区别和协同使用。
  28. 如何通过抓包(tcpdump/wireshark)诊断 Socket 连接问题?
  29. Socket 的非阻塞 accept/read/write 实现注意点(资源/异步安全)。
  30. 如何避免 TCP 粘包/拆包在 Socket 原生编程中的影响(流式协议设计)?
  31. 实战:实现一个带长度前缀的 TCP 协议的 Java 服务端/客户端(思路)。
  32. 如何优雅处理大量短连接的场景?(连接池、HTTP keep-alive)
  33. Socket 端口复用(SO_REUSEADDR vs SO_REUSEPORT)在负载均衡中的用法。
  34. 多路复用(select/poll/epoll)与 socket 大连接数的处理。
  35. 网络字节序(big-endian)与数据编解码注意点。
  36. 使用 TCP_NODELAY(禁用 Nagle)时的 CPU/网络 trade-off。
  37. 如何在 Java 中做到零拷贝文件传输(Socket + FileChannel.transferTo)?
  38. Socket 关闭流程中遇到阻塞(SO_LINGER)的处理办法。
  39. 如何防止或检测 “socket half-closed” 的资源泄漏?
  40. 实战题:用 BIO、NIO、Netty 各实现一个简易的聊天服务器,比较性能与代码复杂度(思路要点)。

七、异步 IO、IO 模型与高阶模式(141–150)

  1. IO 模型分类:同步阻塞、同步非阻塞、IO 多路复用、信号驱动、异步(AIO)。
  2. Reactor 模式与 Proactor 模式的原理与区别。
  3. Java AIO(AsynchronousChannel、AsynchronousSocketChannel)API 介绍。
  4. CompletionHandler 与 Future 风格的异步回调比较。
  5. 高并发下选择 NIO 还是 AIO 的实际考量(实现复杂度、平台支持)。
  6. 事件驱动系统的 back-pressure 设计(流控、速率限制)。
  7. 线程模型设计:acceptors / io workers / business workers 的权衡。
  8. RCU、无锁队列在高并发 IO 框架中的应用场景。
  9. 如何在应用层实现请求队列与排队策略来缓解突发流量?
  10. 实战题:设计一个支持百万连接的服务器架构(核心组件与 IO 策略)。

八、零拷贝、内核与性能调优(151–160)

  1. 零拷贝(zero-copy)概念和常见实现(sendfile, mmap, splice)。
  2. FileChannel.transferTo/transferFrom 在 Linux 下如何利用 sendfile 实现零拷贝?
  3. mmap(内存映射文件)的实现原理与 GC /回收问题。
  4. DMA(Direct Memory Access)在零拷贝中的作用与限制。
  5. 内核态 / 用户态拷贝次数与零拷贝带来的减少效果。
  6. TCP 窗口、拥塞控制调优参数(net.ipv4.tcp_* 系列常见项)。
  7. 系统级调优:文件描述符上限(ulimit -n)、somaxconn、backlog、epoll_limits 等。
  8. 高并发网络服务的监控指标(fd 使用、accept latency、context switch、cpu steal)。
  9. 性能诊断工具与流程:iostat, vmstat, sar, perf, tcpdump, ss, strace。
  10. 实战题:如何定位并修复一个高并发服务器的 accept 阻塞 / 连接丢失 问题(诊断步骤)。

如果你愿意,我可以 接着把每一道题写成“面试级详细解析”:每题包含 —— 概念简述 + 原理/底层机制 + 常见面试追问点 + 典型代码/伪代码(若适用) + 常见坑与性能考量
为了不把单条回复弄得太长,我建议按批次输出解析(例如每批 15–20 题)。

下面我 先示范性地把第 1–10 题写成详细解析,风格如下(概念 + 要点 + 代码/命令 + 面试追问点)。如果你满意这个格式,我会继续按相同风格往下写每批题的解析。


示例:第1–10题 详细解析(示范风格)

1. Java IO 的总体体系结构是什么?

概念
Java IO 可以分为两大类:传统阻塞 IO(java.io)和 NIO(java.nio)。传统 IO 提供字节流(InputStream/OutputStream)、字符流(Reader/Writer)、以及各种装饰器(Buffered、Data、Object 等)。NIO 提供 Buffer、Channel、Selector 及更底层的文件映射(MappedByteBuffer)。

原理 / 要点

  • 传统 IO 基于流(Stream)抽象,面向流式、同步、阻塞操作。
  • NIO 引入 Buffer(内存块)和 Channel(可读写的端点),支持非阻塞和多路复用(Selector),更适合高并发网络 I/O。
  • Java 还有 AIO(Asynchronous IO)作为异步回调风格的补充(java.nio.channels.AsynchronousChannel)。

面试追问点

  • 什么时候用阻塞 IO,什么时候用 NIO?
  • NIO 能否替代传统 IO?(部分场景:文件流仍然方便)
  • AIO 与 NIO 的区别是什么?

2. InputStream / OutputStream 的常见子类有哪些?

要点列举(常见)

  • FileInputStream / FileOutputStream(文件字节流)
  • ByteArrayInputStream / ByteArrayOutputStream(内存字节流)
  • BufferedInputStream / BufferedOutputStream(缓冲)
  • DataInputStream / DataOutputStream(按基本类型读写)
  • ObjectInputStream / ObjectOutputStream(对象序列化)
  • PipedInputStream / PipedOutputStream(管道,用于线程间通信)

面试追问点

  • 什么时候使用 Buffered 流?(I/O 较小且频繁时)
  • DataOutputStream 写的二进制如何跨平台读?(须约定端序)

3. Reader / Writer 的常见子类有哪些?

要点列举(常见)

  • FileReader / FileWriter(字符文件)
  • InputStreamReader / OutputStreamWriter(字节流 ↔ 字符流 适配器)
  • BufferedReader / BufferedWriter(字符缓冲)
  • CharArrayReader / CharArrayWriter(基于字符数组)

面试追问点

  • 为什么不用 FileReader 直接读取所有文本?(编码问题)
  • InputStreamReader 如何指定编码?

4. 字节流与字符流的本质区别和使用场景?

概念

  • 字节流(InputStream/OutputStream)以字节为单位处理数据,适用于二进制数据(图片、音频、视频、压缩包)。
  • 字符流(Reader/Writer)以字符为单位,做了字符解码/编码,适合处理文本。字符流基于字符集(charset),内部通常由 InputStreamReader/OutputStreamWriter 做转换。

面试追问点

  • 处理 UTF-8 文件时用哪种流?(用字节流 + 指定 InputStreamReader 编码,或者 Files.newBufferedReader(Path, Charset))
  • 字符流会不会丢失数据?(若编码/解码不一致会)

5. 为什么要有缓冲流(BufferedInputStream / BufferedReader)?

要点

  • 减少系统调用次数(read 系统调用代价高),提升 I/O 效率。
  • 提供按行读取、标记/重置等高级功能(BufferedReader.readLine(), mark/reset)。
  • 对小、频繁的读写操作特别有效。

代码示例

1
2
3
4
5
6
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
// 处理
}
}

面试追问点

  • BufferedInputStream 的默认缓冲区大小是多少?(通常 8KB,但可构造时指定)
  • 缓冲流什么时候可能不适合使用?(极低延迟、实时数据场景)

6. flush() 与 close() 的区别与细节(含异常处理)

要点

  • flush():将缓冲区中的数据强制写出到底层流,但流仍然可用。适合在不关闭流的情况下确保数据发送。
  • close():先 flush(),再释放资源(关闭底层描述符),关闭后不能再写入。close() 可能抛出异常,要在 finally 或 try-with-resources 中处理。
  • try-with-resources 会自动调用 close,并会将 close 抛出的异常作为 suppressed exception 记录。

面试追问点

  • 为什么要显式 flush?(网络协议的即时发送、日志写入保证等)
  • close 抛出异常时如何处理 suppressed exception?(在 Java 里可通过 Throwable.getSuppressed() 查看)

7. try-with-resources 的工作原理(AutoCloseable、suppressed exceptions)

要点

  • Java 7 引入,任何实现 AutoCloseable 的对象都可以在 try(…) 中声明,try 结束时会自动调用 close()
  • 若 try 块中抛出异常,close 抛出异常会被作为 suppressed 添加到初始异常上,不会覆盖初始异常。
  • 编译器把 try-with-resources 翻译为 finally 块并处理 suppressed。

面试追问点

  • AutoCloseable 与 Closeable 的区别?(Closeable 的 close() 声明抛 IOException;AutoCloseable 更通用)
  • 多个资源按什么顺序关闭?(与声明顺序相反,即后声明先关闭)

8. 装饰器模式在 Java IO 中如何体现?举例链式包装

要点

  • Java IO 将基础流包装成更复杂功能的流:例如 new BufferedReader(new InputStreamReader(new FileInputStream(path))),每一层都是装饰器,扩展了读取能力(缓冲、解码)。
  • 装饰器允许在不改变原始类的情况下添加行为,且可任意组合。

面试追问点

  • 装饰器带来的缺点?(层级过深可读性差、异常处理复杂)

9. File 类的能力与限制(能否读写数据、元数据操作)

要点

  • java.io.File 主要用于表示路径和进行文件/目录的元数据操作(exists, isDirectory, length, renameTo 等),它 不直接读写内容
  • 读写需通过流(FileInputStream/FileOutputStream/FileChannel 等)或 NIO 的 Files 工具类。
  • File 的 renameTo 在不同平台上语义不一致(原子性不可保证)。

面试追问点

  • Java 7 后 Files / Path 提供哪些增强?(更丰富的原子操作、拷贝、移动、文件属性)

10. RandomAccessFile 的用途、指针机制与并发注意点

要点

  • RandomAccessFile 允许在文件中任意位置读取/写入,通过 seek(long pos) 移动文件指针。
  • 适合索引文件、实现简单的数据库、文件内插入/覆盖等。
  • 不是线程安全的;多个线程共享同一个 RandomAccessFile 需外部同步或为每线程打开独立实例(但会增加文件描述符消耗)。

代码示例

1
2
3
4
try (RandomAccessFile raf = new RandomAccessFile("data.bin", "rw")) {
raf.seek(1024);
raf.writeInt(42);
}

面试追问点

  • RandomAccessFile 与 FileChannel 的关系?(RandomAccessFile.getChannel() 可获取 Channel;NIO 更现代)

如果这个示例的详细程度和格式符合你的期望,我会接着按相同格式把 第11–3031–50……分批完整输出,直到把所有 160 题都写成“面试级详解”。我建议每批 15–20 题,这样查阅方便,也便于你随时检索或要求调整深度。

要我继续把接下来的题(11–30)写成详细解析吗?我可以现在开始并把下一批(11–30,共20题)一次性发给你。


当然可以 👍
Java 基础的面试题非常庞杂,我可以帮你继续扩展,补充到更多的维度,甚至超过 200+ 道。之前我给你整理了 150 道,下面我会在原有的基础上,继续补充更多(会覆盖一些面试官经常“刁钻”考的点、源码、陷阱题、实战场景):


Java 基础面试题(继续扩展)

一、语言特性 & 基础语法

  1. Java 中的 ==equals() 有什么区别?如何正确重写 equals()
  2. 为什么重写 equals() 时必须重写 hashCode()?不重写会怎样?
  3. Object 类有哪些方法?哪些方法经常需要重写?
  4. finalfinallyfinalize() 有什么区别?
  5. Java 中的 instanceof 关键字是如何实现的?
  6. 接口和抽象类的区别?接口能不能有构造函数?
  7. 接口可以多继承吗?抽象类可以实现接口吗?
  8. default 方法和 static 方法在接口中的意义是什么?
  9. 什么是内部类?分为哪几种?(成员内部类、静态内部类、局部内部类、匿名内部类)
  10. 匿名内部类和 Lambda 表达式的区别?

二、数据类型 & 内存

  1. Java 中的基本数据类型和包装类型有哪些区别?
  2. 为什么 Integer 有缓存机制?范围是多少?
  3. 为什么 new Integer(127) == new Integer(127) 为 false,而 Integer.valueOf(127) == Integer.valueOf(127) 为 true?
  4. NaNInfinity 在 Java 中如何表示?
  5. 为什么浮点数计算有精度问题?如何避免?
  6. BigDecimal 为什么能解决浮点数精度问题?
  7. Java 中的字符集默认是什么?在不同平台上会不一样吗?
  8. StringStringBuilderStringBuffer 区别?线程安全性?
  9. 为什么 String 是不可变的?背后实现细节?
  10. intern() 方法的作用是什么?

三、集合框架

  1. ArrayListVector 的区别?
  2. 为什么 ArrayList 的扩容是 1.5 倍
  3. LinkedList 是双向链表还是单向链表?
  4. HashSet 底层是如何实现的?
  5. TreeSetTreeMap 的底层实现是什么?
  6. PriorityQueue 的底层数据结构是什么?
  7. ConcurrentSkipListMap 的底层原理是什么?
  8. CopyOnWriteArrayList 的写时复制是怎么实现的?有什么优缺点?
  9. EnumMapEnumSet 是什么?为什么效率高?
  10. WeakHashMapHashMap 的区别?

四、异常 & 错误处理

  1. Java 中的异常分为哪两大类?
  2. ErrorException 的区别?
  3. 受检异常和非受检异常区别?
  4. throwthrows 有什么区别?
  5. try-with-resources 的底层原理是什么?
  6. 自定义异常如何设计?继承哪个类?
  7. 为什么不建议捕获 Throwable
  8. 异常链(Exception Chaining)是什么?
  9. Java 8 之后对异常处理有改进吗?
  10. 如何在多线程环境下正确传递异常?

五、JVM & 内存管理

  1. Java 内存模型(JMM)是什么?
  2. JVM 内存分为哪几个区域?每个区域的作用是什么?
  3. 为什么 String 常量池要放在堆里而不是方法区?
  4. 什么是垃圾回收(GC)的可达性分析算法?
  5. 哪些对象可以作为 GC Roots?
  6. 强引用、软引用、弱引用、虚引用的区别?
  7. GC 有哪些算法?标记-清除、标记-整理、复制算法区别?
  8. 常见的垃圾收集器有哪些?G1、ZGC、Shenandoah 有什么特点?
  9. 什么是 Stop-The-World (STW)?
  10. JVM 调优常见参数有哪些?

六、并发编程基础

  1. Java 中的 volatile 关键字的底层实现原理?
  2. synchronized 的实现原理?对象头和 Monitor 是什么?
  3. 偏向锁、轻量级锁、重量级锁的区别?
  4. 什么是 CAS 操作?ABA 问题如何解决?
  5. 什么是线程安全?举例哪些类是线程安全的?
  6. ThreadLocal 的底层原理是什么?为什么会有内存泄漏问题?
  7. 线程池的核心参数有哪些?
  8. 什么是拒绝策略?
  9. Executors 提供的几种常见线程池?
  10. FutureCompletableFuture 区别?

七、编译 & 运行时

  1. Java 的反射机制是什么?底层原理?
  2. 为什么反射性能差?JDK 9 之后如何优化?
  3. 什么是动态代理?JDK 动态代理和 CGLIB 区别?
  4. 注解的底层原理是什么?运行时注解如何实现?
  5. ClassLoader 的双亲委派模型是什么?
  6. 如何打破双亲委派?
  7. 什么是 SPI(Service Provider Interface)机制?
  8. Java 是如何实现跨平台的?
  9. JIT(即时编译器)优化了哪些东西?
  10. 什么是逃逸分析?

八、常见场景 & 设计

  1. 单例模式在 Java 中有哪些实现方式?哪种最优?
  2. 懒汉模式和饿汉模式的区别?
  3. 枚举单例为什么是最佳实践?
  4. 为什么要用工厂模式?
  5. 装饰器模式和代理模式区别?
  6. Java 中的事件监听模型是怎么实现的?
  7. 为什么 Java 不支持多继承?
  8. 如何用 Java 实现回调机制?
  9. Java 中如何实现观察者模式?
  10. Optional 的设计初衷是什么?

二、Java 并发编程(30题)

  1. 线程的生命周期?
  2. 创建线程的方式有哪些?
  3. Runnable 和 Callable 的区别?
  4. Future 和 CompletableFuture 的区别?
  5. ThreadLocal 原理?
  6. synchronized 的锁优化机制?
  7. ReentrantLock 的实现原理?
  8. 公平锁和非公平锁区别?
  9. 乐观锁和悲观锁区别?
  10. AQS 原理?
  11. CountDownLatch 和 CyclicBarrier 区别?
  12. Semaphore 的实现原理?
  13. Exchanger 的使用场景?
  14. ForkJoinPool 的原理?
  15. CAS 操作的底层实现?
  16. ABA 问题是什么?如何解决?
  17. Atomic 原子类的原理?
  18. BlockingQueue 的实现原理?
  19. ConcurrentHashMap 的分段锁机制?
  20. ConcurrentHashMap 扩容机制?
  21. CopyOnWriteArrayList 的原理?
  22. 线程池的核心参数?
  23. 线程池的拒绝策略?
  24. 线程池的工作流程?
  25. ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 的区别?
  26. 为什么不建议使用 Executors 创建线程池?
  27. JMM 内存可见性问题?
  28. happens-before 规则?
  29. 死锁产生的条件?如何避免?
  30. 常见并发容器有哪些?区别?

三、JVM 与性能优化(30题)

  1. JVM 内存结构?
  2. 堆和栈的区别?
  3. 新生代、老年代、永久代(元空间)的区别?
  4. 对象的创建过程?
  5. 对象的内存分配策略?
  6. GC Roots 有哪些?
  7. 垃圾回收算法有哪些?
  8. CMS 垃圾回收器的工作流程?
  9. G1 垃圾回收器原理?
  10. ZGC 和 Shenandoah 的特点?
  11. Minor GC 和 Full GC 的区别?
  12. OOM 常见类型?如何排查?
  13. 类加载器的分类?
  14. 双亲委派模型的破坏场景?
  15. JVM 常见参数调优?
  16. 内存泄漏和内存溢出的区别?
  17. 逃逸分析是什么?
  18. 方法内联的原理?
  19. JIT 编译器的优化?
  20. Safepoint 机制?
  21. Stop The World 是什么?
  22. Finalize 方法的问题?
  23. JVM 如何判断对象可回收?
  24. TLAB 的作用?
  25. Direct Memory 为什么会 OOM?
  26. Metaspace 的作用?
  27. Full GC 触发条件?
  28. 如何查看 JVM 内存使用情况?
  29. Arthas 常用命令?
  30. JVM 调优常见面试题?

四、Spring & Spring Boot(30题)

  1. Spring 的 IoC 容器原理?
  2. Bean 的生命周期?
  3. BeanFactory 和 ApplicationContext 的区别?
  4. 单例 Bean 如何保证线程安全?
  5. Spring AOP 的实现原理?
  6. JDK 动态代理和 CGLIB 的区别?
  7. Spring 事务的传播机制?
  8. Spring 事务的隔离级别?
  9. @Transactional 的实现原理?
  10. 循环依赖如何解决?
  11. Spring 的三级缓存解决了什么问题?
  12. Spring MVC 的工作流程?
  13. DispatcherServlet 的作用?
  14. Spring Boot 的自动装配原理?
  15. Spring Boot Starter 的机制?
  16. @ConfigurationProperties 和 @Value 的区别?
  17. Spring Boot 如何实现热部署?
  18. Spring Boot 如何处理配置文件?
  19. @Conditional 注解的作用?
  20. Spring Boot 常见的优化点?
  21. Spring 中的事件机制?
  22. ApplicationListener 的使用?
  23. Spring 如何加载配置文件?
  24. Bean 的作用域有哪些?
  25. Spring 如何实现异步调用?
  26. Spring 中的 @Lazy 注解?
  27. Spring 的资源加载机制?
  28. Spring Boot 的内嵌容器有哪些?
  29. Spring Boot Actuator 的作用?
  30. Spring Boot 如何与 Docker/K8s 结合?

五、Spring Cloud(30题)

  1. Spring Cloud 是什么?
  2. Spring Cloud 和 Dubbo 的区别?
  3. Eureka 的工作原理?
  4. Eureka 的自我保护机制?
  5. Ribbon 的负载均衡策略?
  6. Ribbon 和 Nginx 的区别?
  7. Feign 的工作原理?
  8. Feign 如何支持熔断?
  9. Hystrix 的工作原理?
  10. Hystrix 的线程池隔离和信号量隔离?
  11. Resilience4j 和 Hystrix 区别?
  12. Gateway 的核心功能?
  13. Gateway 和 Zuul 的区别?
  14. Config Server 的作用?
  15. Config Server 如何保证配置实时刷新?
  16. Spring Cloud Bus 的原理?
  17. Sleuth 的作用?
  18. Sleuth 与 Zipkin 的关系?
  19. 分布式链路追踪的原理?
  20. Spring Cloud Stream 的作用?
  21. 消息驱动模型和事件驱动模型区别?
  22. Nacos 和 Eureka 的区别?
  23. Nacos 配置中心和注册中心的实现原理?
  24. Sentinel 的工作原理?
  25. 限流的常见算法(令牌桶、漏桶)?
  26. 熔断和降级的区别?
  27. CAP 定理和 Spring Cloud 的关系?
  28. Spring Cloud 与 Kubernetes 的关系?
  29. 微服务中的灰度发布?
  30. Spring Cloud 如何实现服务网格?

六、微服务架构 & 分布式系统(30题)

  1. 什么是微服务?
  2. 微服务与 SOA 的区别?
  3. 微服务的优缺点?
  4. 微服务的拆分原则?
  5. 如何保证微服务之间的数据一致性?
  6. 分布式事务有哪些解决方案?
  7. TCC、SAGA、XA 的区别?
  8. 本地消息表和可靠消息最终一致性?
  9. 分布式锁的实现方式?
  10. Redis 分布式锁的缺陷?
  11. Zookeeper 分布式锁的实现?
  12. 数据库分库分表策略?
  13. 水平拆分与垂直拆分区别?
  14. 分布式 ID 生成方案?
  15. 雪花算法的原理?
  16. API 网关的作用?
  17. 服务注册与发现机制?
  18. 微服务如何保证高可用?
  19. 微服务中的限流和熔断?
  20. 微服务如何保证安全性?
  21. OAuth2 的原理?
  22. JWT 的作用?
  23. 单点登录 SSO 的实现?
  24. 配置中心的作用?
  25. 微服务中的监控体系?
  26. Prometheus 的原理?
  27. ELK 在微服务中的应用?
  28. 服务调用链路追踪的意义?
  29. 服务雪崩效应是什么?
  30. 如何设计一个高并发的微服务系统?

七、数据库 & 缓存(30题)

  1. MySQL 的存储引擎区别?
  2. InnoDB 和 MyISAM 的区别?
  3. MySQL 的事务特性?
  4. MVCC 的实现原理?
  5. MySQL 的索引类型?
  6. 聚簇索引和非聚簇索引?
  7. B+ 树索引原理?
  8. 覆盖索引和回表?
  9. 索引下推优化?
  10. MySQL 的锁机制?
  11. 行锁和表锁区别?
  12. 间隙锁是什么?
  13. 死锁的排查方法?
  14. SQL 执行计划如何分析?
  15. 慢查询优化方法?
  16. 数据库分库分表的难点?
  17. 分布式事务如何保证?
  18. Redis 的数据结构?
  19. Redis 为什么快?
  20. Redis 的持久化机制?
  21. Redis 的过期策略?
  22. Redis 的内存淘汰机制?
  23. Redis 的主从复制原理?
  24. Redis 的哨兵机制?
  25. Redis 的集群模式?
  26. Redis 的分布式锁实现?
  27. Redis 的常见问题?
  28. 缓存穿透、击穿、雪崩?
  29. 如何保证缓存和数据库一致性?
  30. Redis 和本地缓存 Caffeine 的区别?

八、消息队列(30题)

  1. 为什么要使用消息队列?
  2. 消息队列的优缺点?
  3. RabbitMQ 的核心组件?
  4. RabbitMQ 的消息确认机制?
  5. Kafka 的核心概念?
  6. Kafka 的分区机制?
  7. Kafka 的副本机制?
  8. Kafka 的 ISR 原理?
  9. Kafka 的消费组原理?
  10. Kafka 的 offset 提交方式?
  11. Kafka 的高吞吐量原理?
  12. Kafka 的零拷贝机制?
  13. RocketMQ 的核心特点?
  14. RocketMQ 的顺序消息?
  15. RocketMQ 的事务消息?
  16. 如何保证消息不丢失?
  17. 如何保证消息不重复消费?
  18. 如何保证消息有序?
  19. 消息堆积的解决办法?
  20. 如何设计延迟队列?
  21. 死信队列的作用?
  22. 幂等性的实现方式?
  23. 消息队列的限流方式?
  24. 消息队列的监控?
  25. Kafka 和 RabbitMQ 的区别?
  26. Kafka 和 RocketMQ 的区别?
  27. Pulsar 的特点?
  28. 消息中间件如何保证高可用?
  29. 消息队列如何做水平扩展?
  30. 消息队列和事件总线的区别?

九、DevOps & 容器化(30题)

  1. CI/CD 的流程?
  2. Jenkins 的作用?
  3. Docker 的核心原理?
  4. Docker 镜像和容器的区别?
  5. Dockerfile 的常见指令?
  6. 镜像分层机制?
  7. 容器与虚拟机的区别?
  8. Kubernetes 的核心组件?
  9. Pod 的生命周期?
  10. Deployment 和 StatefulSet 区别?
  11. K8s 的服务发现机制?
  12. ConfigMap 和 Secret 的区别?
  13. Ingress 的作用?
  14. K8s 的水平扩缩容机制?
  15. K8s 的滚动更新机制?
  16. K8s 如何做灰度发布?
  17. K8s 的调度策略?
  18. K8s 的网络模型?
  19. Service Mesh 的作用?
  20. Istio 的工作原理?
  21. Helm 的作用?
  22. K8s 的存储方案?
  23. Prometheus 的监控体系?
  24. Grafana 的作用?
  25. K8s 的安全机制?
  26. 容器的资源限制?
  27. Docker Compose 的作用?
  28. DevOps 的最佳实践?
  29. GitOps 的理念?
  30. K8s 如何保证高可用?

十、场景设计题(30题)

  1. 如何设计一个秒杀系统?
  2. 如何设计一个短链系统?
  3. 如何设计一个分布式 ID 生成系统?
  4. 如何设计一个高可用缓存系统?
  5. 如何设计一个订单系统?
  6. 如何设计一个支付系统?
  7. 如何设计一个消息推送系统?
  8. 如何设计一个日志收集系统?
  9. 如何设计一个搜索引擎?
  10. 如何设计一个推荐系统?
  11. 如何设计一个分布式锁?
  12. 如何设计一个统一鉴权系统?
  13. 如何设计一个限流系统?
  14. 如何设计一个灰度发布系统?
  15. 如何设计一个电商购物车?
  16. 如何设计一个库存系统?
  17. 如何设计一个分布式文件存储系统?
  18. 如何设计一个微服务网关?
  19. 如何设计一个分布式任务调度系统?
  20. 如何设计一个监控报警系统?
  21. 如何设计一个高并发聊天室?
  22. 如何设计一个排行榜系统?
  23. 如何设计一个评论系统?
  24. 如何设计一个分布式事务系统?
  25. 如何设计一个高可用注册中心?
  26. 如何设计一个数据同步系统?
  27. 如何设计一个 API 限速系统?
  28. 如何设计一个高可用的支付网关?
  29. 如何设计一个跨境电商架构?
  30. 如何设计一个金融级别的微服务系统?