字符集与编码

共 53 题
📑 题目列表 53 题
#
★★★

1. Charset 在文件读写(Files.newBufferedReader)中显式指定与默认编码的工程价值

在文件读写(如 Files.newBufferedReader)中显式指定 Charset 与使用默认编码的工程价值有何差异?

  • 显式指定 Charset 与默认编码
  • 编码一致性与可移植性
  • 乱码预防

在文件读写中显式指定 Charset(如 Files.newBufferedReader(path, StandardCharsets.UTF_8))能保证编码一致性,避免依赖 JVM 默认编码(file.encoding)造成的可移植性问题。默认编码可能随 JVM 版本、操作系统、环境变量变化(自 JDK 18 默认 UTF-8,但旧系统可能不同),显式指定可确保跨平台一致。工程价值:防止乱码、保证数据交换的一致性、便于国际化与协作。若使用默认编码,不同环境读取同一文件可能得到不同字符,导致数据损坏。最佳实践是显式指定 Charset,尤其在文件读写、网络传输、数据库交互中。理解显式指定 Charset 的价值(一致性、可移植性、防乱码)是本题关键。

核心是显式指定 Charset 保证编码一致与可移植,避免默认编码变化导致乱码。理解其工程价值是本题关键。

try (BufferedReader r = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
    String line = r.readLine();
}
#
★★★

2. GB18030 字符集与 UTF-8 在 Spring Boot 4.0 国际化场景下混用时编码探测的精度如何保障

GB18030 字符集与 UTF-8 在 Spring Boot 4.0 国际化场景下混用时,编码探测的精度如何保障?

  • GB18030 与 UTF-8 的编码混用
  • 编码探测的精度
  • 国际化场景的处理

GB18030 与 UTF-8 都是变长编码,混用时无法仅靠字节判断,因为某些 GB18030 字节序列可能也符合 UTF-8 的结构(或反之),导致编码探测歧义。保障探测精度的措施:通过 BOM(UTF-8 BOM)明确标记;通过 HTTP 头/Content-Type 指定 charset;在业务层约定统一编码(现代国际化统一 UTF-8);对无法确定的数据使用启发式统计(如 ICU CharsetDetector)但需接受误判风险;避免混用,明确数据来源的编码。Spring Boot 4.0 国际化场景下,应统一使用 UTF-8 作为通用编码,避免 GB18030 与 UTF-8 混用,从而规避探测歧义;确需支持 GB18030 时,在边界明确转换并标记。理解 GB18030 与 UTF-8 混用的探测歧义与通过统一编码/BOM/标记保障精度是本题关键。

核心是 GB18030 与 UTF-8 混用探测有歧义,需通过统一编码、BOM、Content-Type 标记保障精度。理解精度的保障方式是本题关键。

#
★★★

3. NIO Charset 在 Linux LANG=C 环境下与 JVM file.encoding 的协商顺序是什么

NIO Charset 在 Linux LANG=C 环境下与 JVM file.encoding 的协商顺序是什么?

  • LANG 环境变量与 file.encoding
  • file.encoding 的确定顺序
  • JDK 18+ 默认 UTF-8

JVM 的 file.encoding 决定默认字符集,其确定顺序从高到低:显式指定 -Dfile.encoding 参数(优先级最高)> JDK 18+ 的默认 UTF-8(JEP 400,若未显式指定则默认 UTF-8,不受 LANG 影响)> 早期版本从 LANG/LC_ALL 环境变量推断。在 JDK 18+(含 JDK 25),即使 Linux LANG=C,file.encoding 默认也是 UTF-8(JEP 400 已落地),不再受 LANG 影响,除非显式用 -Dfile.encoding 覆盖。因此协商顺序是:显式参数优先,其次(JDK 18+)默认 UTF-8,不再依赖 LANG。NIO Charset 默认编码(如 newBufferedReader 不带 charset)会用 file.encoding。理解 file.encoding 的确定顺序(显式参数 > JDK 18+ 默认 UTF-8 > 旧版 LANG 推断)与 LANG=C 的影响是本题关键。

核心是 JDK 18+ 默认 UTF-8(JEP 400),LANG=C 不再影响 file.encoding,显式参数优先。理解协商顺序是本题关键。

#
★★★

4. sun.nio.cs 包的扩展字符集实现

sun.nio.cs 包中的扩展字符集实现是什么?它提供了哪些字符集?

  • sun.nio.cs 包
  • 扩展字符集
  • JDK 内置字符集

sun.nio.cs 是 JDK 的内部包,实现了大量字符集(charset),包括标准字符集与扩展字符集。它提供了 GBK、GB2312、GB18030、Big5、Latin-1、UTF-8、UTF-16 等众多字符集的具体实现类。这些字符集通过 Charset.forName 或 StandardCharsets 使用。sun.nio.cs 是内包(internal),不属于公开 API,开发者不应直接依赖其内部类,但可通过 Charset.forName 按名称访问。JDK 内置的字符集覆盖了主流编码(ASCII、Latin-1、UTF-8/16/32、GBK、GB2312、GB18030、Big5、Shift_JIS、EUC 等)。理解 sun.nio.cs 是 JDK 内部字符集实现包,提供主流编码,应通过 Charset.forName 使用而非直接依赖内部类是本题关键。

核心是 sun.nio.cs 是 JDK 内部字符集实现包,提供 GBK/UTF-8 等主流编码,应通过 Charset.forName 使用。理解其定位与使用方式是本题关键。

#
★★★

5. 文件读写编码一致性(Files.newBufferedReader(path, charset))

文件读写的编码一致性为何重要?Files.newBufferedReader(path, charset) 如何保证?

  • 编码一致性
  • 显式指定 charset
  • 读取与写入的编码匹配

文件读写编码一致性是指文件写入时的编码与读取时的编码一致,否则会产生乱码。Files.newBufferedReader(path, charset) 显式指定读取时的字符集,确保按正确编码解码。同理,Files.newBufferedWriter(path, charset) 指定写入编码。保证一致性:读取与写入使用同一 charset;避免在不同环节混用默认编码;明确约定文件编码(如 UTF-8)。若读取用 UTF-8 而写入用 GBK,则中文乱码。最佳实践是显式指定 charset 并确保读写一致,尤其跨系统、跨语言(如与 Python、C++ 交换文件)时。理解编码一致性(读写同编码)与 newBufferedReader 显式指定 charset 是本题关键。

核心是读写需用同一编码,显式指定 charset 保证一致性,避免乱码。理解一致性要求是本题关键。

#
★★★

6. CSV 文件的分隔符、引号、换行与字符集是独立维度,导入前应怎样检测而不误判内容

CSV 文件的分隔符、引号、换行与字符集是独立维度,导入前应怎样检测而不误判内容?

  • CSV 的多个独立维度
  • 分隔符/引号/换行/字符集检测
  • 避免误判

CSV 文件有多个独立维度:分隔符(逗号、分号、制表符等)、引号(双引号、单引号)、换行符(CRLF、LF)、字符集(UTF-8、GBK 等)。这些维度彼此独立,导入前需分别检测且不能误判内容。检测方法:字符集可通过 BOM 或启发式探测(ICU CharsetDetector);分隔符通过统计字段匹配度(如逗号出现频率、字段数一致性);引号规则通过引号配对与转义分析;换行符通过检测 CRLF/LF 的字节序列。避免误判内容的关键:字段内容本身可能包含逗号、引号、换行(由引号包裹),因此不能简单按分隔符切分,需遵循引号转义规则;检测时应先确认字符集再解析分隔符/引号,避免字符集错误导致内容误判。理解 CSV 各维度独立、检测顺序与引号转义规则是本题关键。

核心是 CSV 的分隔符/引号/换行/字符集独立,需分别检测并遵循引号转义规则避免误判。理解检测与解析方法是本题关键。

#
★★★

7. Charset 与 CharsetProvider 的 SPI 扩展

Charset 与 CharsetProvider 的 SPI 扩展机制是什么?如何实现自定义字符集?

  • CharsetProvider SPI
  • ServiceLoader 机制
  • 自定义字符集

CharsetProvider 是 JDK 提供的字符集服务提供者接口(SPI),允许开发者注册自定义字符集。通过实现 CharsetProvider 抽象类(提供 charsetForName、charsets、aliases 等方法),并在 META-INF/services 中注册(ServiceLoader 机制),JDK 的 Charset.forName 就能找到自定义字符集。Charset 是字符集抽象类,开发者实现 Charset 需提供 CharsetEncoder/CharsetDecoder(编码/解码器)。应用场景:支持业务特定的编码、旧系统私有编码、新编码标准。理解 CharsetProvider 的 SPI 与 ServiceLoader 注册机制、自定义字符集的实现是本题关键。

核心是 CharsetProvider 是 SPI,通过 ServiceLoader 注册,实现自定义 Charset 并提供编码/解码器。理解 SPI 机制是本题关键。

#
★★★

8. CharsetDecoder 的 decode、flush 与 reset 调用顺序是什么,输入结束标记错误会丢失哪些字符

CharsetDecoder 的 decode、flush 与 reset 的调用顺序是什么?输入结束标记错误会丢失哪些字符?

  • decode/flush/reset 调用顺序
  • 流式解码的结束处理
  • 未标记结束的字符丢失

CharsetDecoder 用于字节到字符的解码,正确处理流式解码的调用顺序是:decode(ByteBuffer, CharBuffer, endOfInput) 循环调用(endOfInput 为 false 表示还有输入),处理完所有输入后以 endOfInput=true 调用最后一次 decode,然后必须调用 flush(CharBuffer) 处理等待状态的尾随字节(如多字节序列的剩余字节),最后可调用 reset() 复位解码器以复用。若在输入结束时未正确标记 endOfInput=true 或未调用 flush,解码器可能保留部分未完成的字节序列(如多字节字符的剩余字节),导致这些字符丢失或解码不完整。reset() 用于复位解码器状态以复用解码器。理解 decode/flush/reset 的调用顺序与 endOfInput 标记、未标记结束导致的字符丢失是本题关键。

核心是 decode(循环,endOfInput) -> flush -> reset 的顺序,未标记结束或未 flush 会丢失尾随字节的字符。理解调用顺序与结束处理是本题关键。

#
★★★

9. CharsetEncoder 的 malformedInput 与 unmappableCharacter 处理

CharsetEncoder 的 malformedInput(畸形输入)与 unmappableCharacter(不可映射字符)如何处理?默认行为是什么?

  • malformedInput 与 unmappableCharacter
  • 编码报告策略
  • 默认行为

CharsetEncoder 编码时可能遇到两类错误:malformedInput(输入字节/字符序列非法,如无效的 UTF-8 序列)和 unmappableCharacter(字符在目标字符集中不存在,如将中文"中"编码到 ASCII)。处理策略通过 CodingErrorAction 指定:REPORT(报告错误,抛 MalformedInputException/UnmappableCharacterException)、REPLACE(用替换字符替换,如 '?')、IGNORE(忽略非法字符)。默认行为:CharsetEncoder 默认是 REPORT(报错),但 Java 的 String.getBytes() 等高层 API 默认使用 REPLACE 或特定处理。实际使用中,可通过 onMalformedInput(CodingErrorAction) 和 onUnmappableCharacter(CodingErrorAction) 设置策略。理解两类错误与 REPORT/REPLACE/IGNORE 策略及默认行为是本题关键。

核心是 malformedInput 与 unmappableCharacter 两类错误,策略为 REPORT/REPLACE/IGNORE,默认 REPORT。理解错误类型与策略是本题关键。

#
★★★

10. CharsetEncoder/CharsetDecoder 在编码异常下的处理

CharsetEncoder/CharsetDecoder 在编码异常下如何处理?如何保证数据安全?

  • 编码异常的类型
  • 异常处理策略
  • 数据安全

CharsetEncoder/CharsetDecoder 在编码异常下(如畸形输入、不可映射字符)默认抛异常(MalformedInputException、UnmappableCharacterException),以保证数据安全(不静默丢失或篡改数据)。开发者可通过 onMalformedInput/onUnmappableCharacter 设置 CodingErrorAction 调整策略:REPORT(抛异常,最安全)、REPLACE(替换字符,容忍但不安全)、IGNORE(忽略,可能丢失数据)。保证数据安全的原则:对关键数据(如数据库、文件)使用 REPORT 或 REPLACE 并记录,避免 IGNORE 静默丢数据;在数据边界明确编码并校验。解码同理:对待畸形字节序列应明确处理(REPORT/REPLACE),避免产生错误字符。理解编码异常类型与策略选择、数据安全是本题关键。

核心是编码异常默认抛异常保证数据安全,可通过 CodingErrorAction 调整策略,关键数据避免 IGNORE。理解异常处理与数据安全是本题关键。

#
★★★

11. DataInputStream 的 readUTF 变长编码与网络协议中长度前缀协议的配合

DataInputStream 的 readUTF 变长编码与网络协议中长度前缀协议如何配合?

  • readUTF 的变长编码
  • 长度前缀协议
  • 网络协议配合

DataInputStream.readUTF() 读取以 Modified UTF-8 编码的字符串,其格式是"2 字节长度前缀 + 变长 UTF-8 数据",readUTF 先读取 2 字节长度(无符号 short),再按长度读取对应字节并解码。这与网络协议中的长度前缀(length-prefixed)协议思想一致:先约定长度,再发送数据,接收方按长度读取,避免粘包/拆包问题。配合方式:发送方用 DataOutputStream.writeUTF() 写入(自动加 2 字节长度前缀),接收方用 readUTF() 读取(先读长度再读数据)。长度前缀协议的核心是"先定界再传输",解决网络流的分帧问题。注意 readUTF 的 Modified UTF-8 与标准 UTF-8 有差异(如 0 字节编码成 C0 80),且长度用 2 字节(上限 65535)。理解 readUTF 的长度前缀格式与网络分帧协议的配合是本题关键。

核心是 readUTF 用 2 字节长度前缀 + 变长 UTF-8,与网络长度前缀协议一致,解决分帧。理解格式与配合是本题关键。

#
★★★

12. Emoji 表情字符(4 字节 UTF-8)在 String.length() 与 codePointCount 上的偏差如何影响业务截取

Emoji 表情字符(4 字节 UTF-8)在 String.length() 与 codePointCount 上的偏差如何影响业务截取?

  • String.length() 与 codePointCount
  • Emoji 的代理对与变长
  • 业务截取的正确性

Java String 内部用 UTF-16(char 数组)存储,String.length() 返回 char 数(UTF-16 code unit),而 codePointCount() 返回 Unicode 码点数。Emoji 等补充平面字符(如 U+1F600)在 UTF-16 中用代理对(surrogate pair)表示,即两个 char,所以 length() 为 2 而 codePointCount() 为 1。部分 Emoji 甚至由多个码点组成(含 ZWJ 连接符或变体选择符),如肤色修饰。业务截取时若用 length() 按字符数截取,可能切断代理对或把多码点 Emoji 截断,产生乱码或破坏字符。正确做法:用 codePointCount 与 codePointAt 按码点截取,或使用 grapheme(字素簇)级别截取(如 ICU BreakIterator),避免切断用户感知的字符。理解 length() 与 codePointCount 的偏差及对截取的影响是本题关键。

核心是 Emoji 用代理对/多码点,length() 与 codePointCount 偏差,截取需按码点或字素簇避免切断。理解偏差与截取方法是本题关键。

#
★★

13. GBK/GB2312/GB18030 的中文编码边界

GBK、GB2312、GB18030 的中文编码边界是什么?它们有何区别与兼容关系?

  • GB2312/GBK/GB18030 的关系
  • 编码范围与兼容
  • 边界差异

GB2312 是最早的中文编码标准,覆盖常用汉字(约 6763 个),采用双字节编码(区位码),是 GBK 的始祖。GBK 是 GB2312 的扩展,兼容 GB2312,增加了更多汉字(约 2 万+),仍为双字节。GB18030 是 GBK 的扩展,采用变长编码(1/2/4 字节),兼容 GBK 与 GB2312,并覆盖 Unicode 全部码点(包括补充平面),是最新的中文编码标准。边界:GB2312 只覆盖常用汉字,GBK 覆盖更多,GB18030 覆盖全部 Unicode;三者向后兼容(GB18030 兼容 GBK 兼容 GB2312)。选择:现代系统优先 UTF-8,若需兼容旧数据用 GBK/GB18030。理解三者的覆盖范围与兼容关系(GB18030 兼容 GBK 兼容 GB2312)是本题关键。

核心是 GB2312 最基础、GBK 扩展、GB18030 变长覆盖全部 Unicode,三者向后兼容。理解覆盖与兼容边界是本题关键。

#
★★

14. GBK/UTF-8/ISO-8859-1 在中文文本处理中的乱码根因与 Charset.forName 解析

GBK/UTF-8/ISO-8859-1 在中文文本处理中的乱码根因是什么?Charset.forName 如何解析?

  • 编码不一致的乱码根因
  • ISO-8859-1 的特性
  • Charset.forName 解析

中文乱码的根因是编码不一致:写入时用某编码(如 GBK),读取时用另一编码(如 UTF-8),导致字节序列被错误解码。ISO-8859-1(Latin-1)是单字节编码,只覆盖 0-255,不包含中文,用 ISO-8859-1 解码 UTF-8/GBK 的中文字节会得到乱码字符(每个字节解码为一个 Latin-1 字符)。Charset.forName(String) 按名称查找字符集,支持别名(如 "UTF-8"、"GBK"、"ISO-8859-1"、"Latin-1"),找不到抛 UnsupportedCharsetException。乱码根因处理:确认编码来源,用正确编码解码;避免用 ISO-8859-1 处理中文(除非是字节流失真的场景)。理解乱码根因(编码不一致)与 ISO-8859-1 单字节特性、Charset.forName 的别名解析是本题关键。

核心是乱码根因是编码不一致,ISO-8859-1 单字节不含中文,Charset.forName 按名称/别名解析。理解根因与解析是本题关键。

#
★★

15. InputStream/OutputStream 与 Reader/Writer 的分工与 InputStreamReader 桥接的字符集转换

InputStream/OutputStream 与 Reader/Writer 的分工是什么?InputStreamReader 如何桥接字符集转换?

  • 字节流与字符流的分工
  • InputStreamReader 桥接
  • 字符集转换

InputStream/OutputStream 是字节流,处理原始字节数据(二进制),不涉及字符集;Reader/Writer 是字符流,处理字符(文本),内部涉及字符集转换(字节/字符)。InputStreamReader 是二者之间的桥接:它把字节流(InputStream)包装为字符流(Reader),在读取时按指定字符集将字节解码为字符。同理 OutputStreamWriter 把字符流编码为字节流输出。通过指定 Charset,InputStreamReader 控制解码的字符集,避免乱码。分工:处理二进制用字节流,处理文本用字符流(配合编码)。理解字节流与字符流的分工、InputStreamReader 的桥接与字符集转换是本题关键。

核心是字节流处理二进制、字符流处理文本,InputStreamReader 桥接并按字符集解码。理解分工与桥接是本题关键。

#
★★

16. JDK 25 中 Charset.forName 与 StandardCharsets 的查找性能差异主要来自哪段缓存逻辑

JDK 25 中 Charset.forName 与 StandardCharsets 的查找性能差异主要来自哪段缓存逻辑?

  • StandardCharsets 的常量引用
  • Charset.forName 的查找缓存
  • 性能差异来源

StandardCharsets 中的常量(如 StandardCharsets.UTF_8)是静态 final 的 Charset 实例,直接引用,无需任何查找,性能最高。Charset.forName(name) 需要按名称查找字符集,其查找过程:先在 JDK 内置字符集的缓存中查找(Charset 类维护一个缓存),命中则返回;未命中则通过 ServiceLoader 查找 Provider 的字符集。因此 forName 的性能差异来自查找/缓存逻辑:虽然 forName 有缓存(首次查找后缓存实例),但每次调用仍涉及名称匹配与缓存查找的开销,且需处理别名、异常检查。差距主要体现在调用次数多时(forName 有字符串匹配与缓存查询开销),而 StandardCharsets 是零查找的直接引用。理解 StandardCharsets 直接引用与 forName 的缓存查找逻辑是性能差异来源是本题关键。

核心是 StandardCharsets 直接引用无查找,forName 有缓存查找与名称匹配开销。理解差异来源是本题关键。

#
★★

17. JSON 传输通常采用 UTF-8,但响应头与实际字节不一致时,客户端应信任哪一层并如何告警

JSON 传输通常采用 UTF-8,但响应头(Content-Type 的 charset)与实际字节不一致时,客户端应信任哪一层并如何告警?

  • 响应头 charset 与实际字节不一致
  • 信任层级与优先级
  • 告警机制

当响应头声称的 charset 与实际字节不一致时,客户端应有明确的信任策略:优先信任响应头(Content-Type 的 charset)作为约定的解码依据,因为这是服务端显式声明的协议;但若按响应头解码失败(如出现畸形字节)或结果明显异常,应回退到实际字节检测(如 BOM、启发式)并告警。实践中,很多客户端(如 HTTP 客户端)以响应头 charset 为准,若与实际不符则可能导致乱码。告警方式:记录日志(警告响应头 charset 与实际字节不一致)、上报监控指标、在解析失败时抛出明确异常并提示。最佳实践是服务端保证结构一致(Content-Type 与实际编码统一),客户端检测到不一致时告警并回退。理解信任层级(响应头优先,异常时回退检测并告警)是本题关键。

核心是响应头 charset 优先,解码失败时回退字节检测并告警,服务端应保证一致性。理解信任与告警策略是本题关键。

#
★★

18. 如何复用 CharsetEncoder/CharsetDecoder 避免每次 getBytes/new String 的分配开销,线程安全如何保证

如何复用 CharsetEncoder/CharsetDecoder 避免每次 getBytes/new String 的分配开销?线程安全如何保证?

  • CharsetEncoder/Decoder 复用
  • 避免分配开销
  • 线程安全保证

CharsetEncoder/CharsetDecoder 是有状态的(维护内部状态、缓冲区),复用可避免每次 getBytes/new String 时创建新编码器/解码器的分配开销。复用方式:将 CharsetEncoder/Decoder 作为 ThreadLocal 存储(每个线程一个实例),避免多线程共享而导致的线程安全问题;或用对象池管理。线程安全:CharsetEncoder/Decoder 不是线程安全的(有内部状态),不能跨线程共享,因此用 ThreadLocal 保证每个线程独立实例,或在使用时加锁(但破坏了并发)。保证线程安全的关键是 ThreadLocal 隔离或池化 + 借用/归还。复用后可调用 reset() 复位状态再复用。理解复用降低分配开销、通过 ThreadLocal 或池化保证线程安全是本题关键。

核心是 Encoder/Decoder 有状态非线程安全,复用需 ThreadLocal 或池化隔离,注意 reset 复位。理解复用与线程安全是本题关键。

#
★★

19. Java 字符串(UTF-16)与字节流的相互转换

Java 字符串(UTF-16 内部存储)与字节流如何相互转换?

  • String 与 byte[] 互转
  • getBytes/new String
  • 编码与解码

Java String 内部用 UTF-16 存储,与字节流互转通过 getBytes 和 new String。String.getBytes(Charset) 将字符串按指定字符集编码为 byte[];new String(byte[], Charset) 将字节数组按指定字符集解码为 String。转换需显式指定 Charset,否则用默认编码(自 JDK 18 默认 UTF-8)。编码时字符集决定每个字符的字节表示(如 UTF-8 变长、GBK 双字节);解码时用相同字符集才能还原。互转的正确性依赖于编码一致性:编码与解码用同一字符集。注意单字节字符(ASCII)在 UTF-8/GBK 下都是 1 字节,但中文等在不同字符集下字节数不同。理解 String 与字节流的互转(getBytes/new String 指定 Charset)与编码一致性是本题关键。

核心是 getBytes 编码、new String 解码,需指定同一 Charset 保证还原。理解互转与一致性是本题关键。

byte[] bytes = "你好".getBytes(StandardCharsets.UTF_8);
String text = new String(bytes, StandardCharsets.UTF_8);
#
★★

20. Java 的 UTF-16 内部字符存储与 Unicode 17(最新标准)

Java 的 UTF-16 内部字符存储与 Unicode 17(最新标准)有何关系?

  • Java 的 UTF-16 存储
  • Unicode 17 与码点
  • 代理对与补充平面

Java 的 String 内部用 UTF-16 存储字符(char 数组),BMP(基本多文种平面,U+0000 至 U+FFFF)内的字符占一个 char,补充平面(U+10000 以上)的字符用代理对(两个 char)表示。Unicode 17 是最新 Unicode 标准,包含更多新字符与符号,但码点体系不变(最大 U+10FFFF)。Java 的 UTF-16 存储能表示所有 Unicode 码点(通过代理对),因此与 Unicode 17 兼容。Unicode 17 新增的字符可能落在补充平面,用代理对表示,Java 可通过 codePointAt/codePointCount 处理。理解 Java UTF-16 存储(BMP 单 char、补充平面代理对)与 Unicode 17 码点体系的关系是本题关键。

核心是 Java 用 UTF-16(BMP 单 char、补充平面代理对)表示所有 Unicode 码点,与 Unicode 17 兼容。理解存储与码点关系是本题关键。

#
★★

21. Java 默认字符集自 JDK 18 统一为 UTF-8 后,旧系统迁移仍需检查哪些文件和启动参数

Java 默认字符集自 JDK 18 统一为 UTF-8 后,旧系统迁移仍需检查哪些文件和启动参数?

  • JEP 400 默认 UTF-8
  • 迁移检查点
  • 启动参数与文件编码

JDK 18 起(JEP 400)默认字符集统一为 UTF-8,不再依赖操作系统/LANG。旧系统迁移到新高版本时,需检查:硬编码依赖默认编码的代码(如 String.getBytes() 无参数、new String(byte[]) 无参数、Files.readAllLines 无 charset),这些现在用 UTF-8 而非原默认编码;Properties.load(InputStream) 默认 ISO-8859-1 与 load(Reader) 不同;启动参数 -Dfile.encoding(若显式指定与目标不符);读取的旧文件编码(若为 GBK 等需显式指定);日志/输出流的编码;数据库连接字符集。迁移时应显式指定 Charset,避免依赖默认编码,并审查所有隐式使用默认编码的位置。理解迁移时需检查隐式默认编码使用、启动参数与旧文件编码是本题关键。

核心是迁移时代码/文件/参数中隐式依赖默认编码的位置需审查,显式指定 Charset。理解迁移检查点是本题关键。

#
★★

22. MIME charset 头与 Content-Type 在 HTTP/2 场景下的字符集协商机制差异是什么

MIME charset 头与 Content-Type 在 HTTP/2 场景下的字符集协商机制差异是什么?

  • Content-Type 的 charset 参数
  • HTTP/2 的字符集协商
  • 协商机制差异

Content-Type 头通过 charset 参数(如 Content-Type: text/html; charset=utf-8)声明正文的字符集。HTTP/1.1 与 HTTP/2 都通过 Content-Type 的 charset 参数进行字符集协商,机制上基本一致;HTTP/2 的差异主要体现在传输层(二进制分帧、压缩头),不影响 Content-Type 的 charset 语义。HTTP/2 没有单独的字符集协商机制,仍依赖 Content-Type 的 charset 或规范默认(如 JSON 默认 UTF-8)。协商差异:若响应不指定 charset,客户端按规范默认或启发式猜测;HTTP 头本身(如 Accept-Charset)在现代 HTTP/2 中较少使用。因此字符集协商仍以 Content-Type 的 charset 为主,HTTP/2 的改进主要在传输层而非字符集语义。理解 Content-Type charset 是字符集协商核心,HTTP/2 差异主要在传输层是本题关键。

核心是字符集协商靠 Content-Type 的 charset,HTTP/2 差异在传输层(分帧/压缩)而非字符集语义。理解协商机制是本题关键。

#
★★

23. PrintStream(System.out)的自动刷新与字符集编码在重定向日志时的陷阱

PrintStream(System.out)的自动刷新与字符集编码在重定向日志时有哪些陷阱?

  • PrintStream 自动刷新
  • 字符集编码
  • 重定向日志的陷阱

System.out 是 PrintStream,默认不自刷新(autoFlush 根据构造参数),重定向日志时若不及时 flush,可能丢失或延迟输出。PrintStream 的构建可指定字符集(PrintStream(OutputStream, boolean, Charset)),若未指定用默认编码,重定向到文件时若编码与文件预期不符会产生乱码。陷阱:System.out 默认行缓冲/不自动刷新,重定向到文件时缓冲未被及时刷新(尤其程序异常退出时丢失);编码用默认字符集(不同环境可能不同);PrintStream 吞掉异常(checkError 只是标记,不抛出),导致编码错误被静默。建议:重定向日志时显式指定编码、及时 flush(或使用 autoFlush)、避免依赖 System.out 自身编码,用日志框架(如 Logback)管理输出。理解 PrintStream 自动刷新与编码、重定向陷阱是本题关键。

核心是 PrintStream 缓冲/自动刷新、默认编码、吞异常三个陷阱,重定向日志需显式编码与及时 flush。理解陷阱是本题关键。

#
★★

24. Properties.load(InputStream) 与 load(Reader) 的编码语义有何差异,现代配置应如何避免转义依赖

Properties.load(InputStream) 与 load(Reader) 的编码语义有何差异?现代配置应如何避免转义依赖?

  • load(InputStream) 与 load(Reader) 的编码差异
  • Properties 的默认编码
  • 现代配置避免转义

Properties.load(InputStream) 按 ISO-8859-1(Latin-1)读取,因为 Properties 文件规范默认 ISO-8859-1;load(Reader) 按 Reader 的字符集读取(可指定 UTF-8)。因此 load(InputStream) 处理中文需用 \uXXXX 转义,否则乱码;load(Reader) 可用 UTF-8 直接写中文。现代配置避免转义依赖:使用 load(Reader) 并指定 UTF-8(Properties.load(Reader) 配合 UTF-8),或使用 loadFromXML(UTF-8 编码的 XML),或改用 YAML/JSON 等现代配置格式(Spring Boot 等)避免 Properties 的转义限制。理解 load(InputStream) 默认 ISO-8859-1 与 load(Reader) 支持指定编码、现代配置避免转义是本题关键。

核心是 load(InputStream) 默认 ISO-8859-1 需转义,load(Reader) 可指定编码,现代配置用 UTF-8/XML/YAML 避免转义。理解差异是本题关键。

#
★★

25. REPORT、REPLACE 与 IGNORE 三种编码错误策略各有什么数据风险,服务端默认应如何选择

REPORT、REPLACE 与 IGNORE 三种编码错误策略各有什么数据风险?服务端默认应如何选择?

  • 三种编码错误策略
  • 各自的数据风险
  • 服务端策略选择

三种编码错误策略(CodingErrorAction):REPORT(报告错误,抛异常)最安全,拒绝非法数据,风险是处理被中断、可能拒绝合法数据边界;REPLACE(用替换字符替换)容忍错误,但会静默篡改数据(替换为 '?' 等),数据虽不中断但内容受损,且可能不被察觉;IGNORE(忽略)最危险,会静默丢弃非法字符,数据丢失且难以察觉,可能导致数据不完整或语义错误。服务端默认应选择 REPORT(或 REPLACE 并记录告警),确保数据安全与可追溯,避免 IGNORE 静默丢数据。对用户输入、数据入库等关键数据,应 REPORT 严格校验;对日志等非关键数据可 REPLACE 容忍。理解三种策略的数据风险与服务端默认选择 REPORT 是本题关键。

核心是 REPORT 安全、REPLACE 篡改数据、IGNORE 丢数据,服务端默认 REPORT 保证数据安全。理解风险与选择是本题关键。

#
★★

26. StandardCharsets 在 JDK 17 的新增

StandardCharsets 在 JDK 17 新增了哪些内容?

  • StandardCharsets 的常量
  • JDK 17 的变更
  • 字符集常量范围

StandardCharsets 类提供常用字符集的常量:US_ASCII、ISO_8859_1、UTF_8、UTF_16、UTF_16BE、UTF_16LE。这些常量自 JDK 7 引入 StandardCharsets 时即全部提供(UTF_16 系列并非 JDK 17 新增,JDK 17 未新增字符集常量)。这些常量是静态 final,可直接引用、避免 Charset.forName 字符串,性能好且类型安全。理解 StandardCharsets 提供的常用字符集常量(尤其 UTF_16 系列)自 JDK 7 起就已存在、JDK 17 并无扩充是本题关键。

核心是 StandardCharsets 自 JDK 7 起即提供常用字符集常量(含 UTF_16 系列),JDK 17 并未新增常量。理解常量范围是本题关键。

#
★★

27. StandardCharsets.UTF_8 与 Charset.forName 的差异

StandardCharsets.UTF_8 与 Charset.forName("UTF-8") 有何差异?

  • 常量引用与名称查找
  • 性能与类型安全
  • 返回值差异

StandardCharsets.UTF_8 是静态 final 的 Charset 实例,直接引用,无查找开销,类型安全,编译期可检查;Charset.forName("UTF-8") 按名称查找,运行时进行名称匹配与缓存查找,若名称无效抛 UnsupportedCharsetException。两者返回的 Charset 是同一个实例(UTF-8 的 Charset 单例),因此功能等价,但 StandardCharsets.UTF_8 性能更好、无异常风险、更推荐。差异主要在于:StandardCharsets 是编译期常量引用(快、无异常),forName 是运行时查找(慢、可能抛异常、需处理名称)。理解 StandardCharsets 常量引用优于 forName 的名称查找(性能与异常)是本题关键。

核心是 StandardCharsets 直接引用快无异常,forName 运行时查找可能抛异常。理解差异是本题关键。

#
★★

28. String.length、codePointCount 与 UTF-8 字节数为何不同,数据库字段限长应按哪种单位校验

String.length、codePointCount 与 UTF-8 字节数为何不同?数据库字段限长应按哪种单位校验?

  • length 与 codePointCount 与字节数差异
  • 各单位的字符度量
  • 数据库字段限长校验

String.length() 返回 UTF-16 的 char 数(code unit),codePointCount() 返回 Unicode 码点数,getBytes(UTF_8).length 返回 UTF-8 编码后的字节数。三者不同:中文字符 UTF-8 占 3 字节、UTF-16 占 1 个 char(BMP)但码点 1;Emoji(补充平面)UTF-8 占 4 字节、UTF-16 占 2 个 char(代理对)、码点 1。数据库字段限长应按哪种单位校验取决于数据库定义:若数据库字段是 VARCHAR(n)(按字符/码点或字节,取决于数据库与配置),Oracle 的 VARCHAR2(n CHAR) 按字符、MySQL 的 VARCHAR(n) 按字符(utf8mb4),但存储字节数不同。校验应匹配数据库实际存储单位:若数据库按字节限长,则校验 UTF-8 字节数;若按字符,则校验码点或字符数。通常更稳妥的是按字节数校验(因为存储成本是字节),并明确数据库字段单位。理解三者差异与按数据库存储单位校验是本题关键。

核心是 length 是 UTF-16 char 数、codePointCount 是码点数、字节数是 UTF-8 长度,校验应与数据库实际存储单位匹配。理解差异与校验单位是本题关键。

#
★★

29. URL 编码(URLEncoder/URLDecoder)

URLEncoder/URLDecoder 的 URL 编码是什么?有哪些注意事项?

  • URLEncoder/URLDecoder 的编码规则
  • 与 URL 标准编码的差异
  • 注意事项

URLEncoder.encode(String) 将字符串编码为 application/x-www-form-urlencoded 格式(表单编码),空格转为 +,非 ASCII 与特殊字符按 UTF-8 字节转 %XX;URLDecoder.decode(String) 反向解码。注意:URLEncoder 编码的是表单(query parameter)而非 RFC 3986 的 URL 路径编码,因此空格编为 + 而非 %20,这在路径编码中不适用。指定字符集时(URLEncoder.encode(String, Charset))可控制编码。注意事项:URL 路径与 query 用不同编码规则;URLEncoder 默认 UTF-8(JDK 10+ 无参版本已弃用,需指定 Charset);解码与编码需用同一字符集。理解 URLEncoder 的表单编码(空格为 +)与 URL 路径编码差异、指定字符集是本题关键。

核心是 URLEncoder 是表单编码(空格为 +)而非路径编码,需指定字符集。理解其规则与差异是本题关键。

#
★★

30. UTF-8 BOM 在文本文件中可选但在协议字段中可能成为内容,读取时应如何明确处理

UTF-8 BOM 在文本文件中可选但在协议字段中可能成为内容,读取时应如何明确处理?

  • UTF-8 BOM 的概念
  • BOM 在文件与协议中的差异
  • 读取时的处理

UTF-8 BOM(字节顺序标记)是 EF BB BF 三个字节,用于标识 UTF-8 编码。在文本文件中,BOM 可选(现代 UTF-8 通常无 BOM),文件读取工具通常能跳过 BOM。但在协议字段(如 HTTP 字段、JSON 文本)中,BOM 会被当作内容的一部分(如 JSON 解析器把 BOM 当非法字符),导致解析失败。读取时应明确处理:读取文件时检测 BOM 并跳过(若存在);处理协议字段时移除 BOM(如 JSON 解析前 strip BOM);存储时明确约定是否带 BOM。处理方式:用 FileInputStream 读取前 3 字节判断 BOM 并跳过,或用 BufferedReader 配合 BOMInputStream 跳过。理解 BOM 在文件与协议中的差异、读取时明确检测与跳过是本题关键。

核心是 BOM 在文件可选、在协议成为内容,读取时检测并跳过。理解 BOM 的差异与处理是本题关键。

#
★★

31. UTF-8 的过长编码、孤立续字节和代理码点为什么属于非法输入,安全校验应在哪层完成

UTF-8 的过长编码、孤立续字节和代理码点为什么属于非法输入?安全校验应在哪层完成?

  • UTF-8 的非法序列
  • 过长编码/孤立续字节/代理码点
  • 安全校验层级

UTF-8 的合法编码有严格规则,以下情况属于非法输入:过长编码(overlong encoding,如用多字节编码本可用单字节表示的码点,如 0xC0 0x80 表示 U+0000),可能被用于绕过过滤;孤立续字节(continuation byte 无起始字节,或起始字节后缺续字节);代理码点(U+D800 至 U+DFFF,UTF-8 明确禁止编码代理码点,因为只能用于 UTF-16 代理对)。这些非法序列可能导致安全漏洞(如路径穿越、注入绕过)或解码歧义。因此安全校验应在输入边界完成:在解码前校验 UTF-8 合法性(如 CharsetDecoder 的 REPORT 策略拒绝畸形输入),在协议层、安全框架层统一校验,避免上层依赖非法字节。正确做法是使用严格解码器(REPORT 策略)拒绝非法 UTF-8,并在应用入口(如 Web 框架、API 网关)校验。理解非法 UTF-8 序列的类型与安全校验应在输入边界完成是本题关键。

核心是过长编码/孤立续字节/代理码点是非法 UTF-8,安全校验应在输入边界用严格解码器完成。理解非法类型与校验层级是本题关键。

#
★★

32. UTF-8/UTF-16/UTF-32 的差异与 BOM

UTF-8、UTF-16、UTF-32 有何差异?BOM 的作用是什么?

  • UTF-8/16/32 的编码差异
  • BOM 与字节序
  • 适用场景

UTF-8 是变长编码(1 到 4 字节),ASCII 兼容,无字节序问题,节省空间,是网络与文件的通用标准。UTF-16 是变长编码(2 或 4 字节,补充平面用代理对),有字节序(大端/小端)问题,需 BOM 或指定端序。UTF-32 是定长编码(4 字节),每个码点固定 4 字节,有字节序问题,空间浪费大,但随机访问简单。BOM(字节顺序标记)用于标识字节序(UTF-16/32 的 FE FF 或 FF FE)或标识 UTF-8 编码(EF BB BF)。差异:UTF-8 兼容 ASCII、无字节序、节省空间;UTF-16/32 有字节序问题、空间更大。适用场景:UTF-8 用于网络与文件(JSON 等);UTF-16 用于 Java/Windows 内部;UTF-32 用于需要常数时间随机访问的场景。理解三者的变长/定长、字节序与 BOM 作用是本题关键。

核心是 UTF-8 变长兼容 ASCII 无字节序、UTF-16 变长有字节序、UTF-32 定长有字节序,BOM 标识字节序/编码。理解差异与 BOM 是本题关键。

#
★★

33. Unicode NFC 与 NFKC 的规范化目标有何差异,用户名或签名输入为何不能随意选择兼容分解

Unicode NFC 与 NFKC 的规范化目标有何差异?用户名或签名输入为何不能随意选择兼容分解?

  • NFC 与 NFKC 规范化
  • 兼容分解 vs 规范分解
  • 安全与一致性

Unicode 规范化有四种形式:NFC(规范分解后规范组合)、NFD(规范分解)、NFKC(兼容分解后规范组合)、NFKD(兼容分解)。NFC 只做规范分解与组合(保留原有字符语义,如 é 规范组合为单个码点),NFKC 做兼容分解(把兼容字符如全角、连字、圈号分解为更基础的字符,可能改变语义)。差异:NFKC/NFKD 会改变字符的形式(如全角 A 与半角 A、fi 连字分解为 f+i),可能导致视觉不同但语义等价的字符被统一。用户名或签名输入不能随意选择兼容分解(NFKC/NFKD)的原因:兼容分解可能改变用户感知的标识(如把特殊字符分解为普通字符),导致不同用户名被归一化冲突,或破坏签名/标识的原始语义与安全性;而 NFC 保留字符语义,适合规范化为等价形式。用户名通常用 NFC(规范等价)而非 NFKC(兼容分解),避免破坏特殊字符。理解 NFC 与 NFKC 的差异(规范 vs 兼容)及用户名不应随意用兼容分解是本题关键。

核心是 NFC 规范等价、NFKC 兼容分解可能改变语义,用户名应用 NFC 避免破坏特殊字符。理解差异与选择是本题关键。

#
★★

34. Unicode Normalization(Normalizer.normalize)在跨语言文本比较与排序中的工程价值

Unicode Normalization(Normalizer.normalize)在跨语言文本比较与排序中的工程价值是什么?

  • Normalizer.normalize 规范化
  • 跨语言比较与排序
  • 规范化对一致性的作用

Unicode 规范化(Normalizer.normalize)将文本统一为规范形式(如 NFC),解决"同一字符可有多种编码表示"的问题(如 é 用单个码点 U+00E9 或 e+组合音标 U+0065 U+0301)。在跨语言文本比较与排序中,规范化保证等价文本被统一,避免因编码表示不同导致比较不一致或排序错乱。工程价值:用户输入、数据库存储、搜索索引、去重中先规范化,保证一致性;比较时用规范化后的文本。排序还需结合 Collator(语言感知排序)与规范化。理解 Normalizer.normalize 统一等价文本、在跨语言比较/排序中保证一致性的工程价值是本题关键。

核心是规范化统一等价文本(如 é 的不同表示),保证跨语言比较与排序一致。理解其工程价值是本题关键。

#
★★

35. Unicode 码点、UTF-16 code unit 与用户感知字素簇有何区别,字符串截断应以哪一层为准

Unicode 码点、UTF-16 code unit 与用户感知的字素簇有何区别?字符串截断应以哪一层为准?

  • 码点与 code unit 与字素簇
  • 三者的层级差异
  • 截断的正确层级

Unicode 码点(code point)是每个字符的基本单元(如 U+0041);UTF-16 code unit 是 UTF-16 编码单元(char),BMP 字符一个码点对应一个 code unit,补充平面用两个 code unit(代理对);字素簇(grapheme cluster)是用户感知的"字符",可能由多个码点组成(如 é = e + 组合音标,或 Emoji + 肤色修饰 + ZWJ 连接)。三者层级递增:字素簇 ≥ 码点 ≥ code unit。字符串截断应以用户感知的字素簇为准,避免切断码点(半个代理对)或破坏组合字符(如截断 e 与音标)。实现:按码点截断用 codePointAt/codePointCount,按字素簇截断用 ICU BreakIterator(副词 getCharacterInstance)或字符簇边界。理解三者层级与截断应以字素簇为准是本题关键。

核心是码点 < 字素簇层级,截断应把握字素簇边界避免切断码点或组合字符。理解层级与截断层级是本题关键。

#
★★

36. charset 读取失败应回退到 UTF-8 还是 ISO-8859-1

charset 读取失败时应回退到 UTF-8 还是 ISO-8859-1?各自的依据是什么?

  • 回退方案的选择
  • UTF-8 与 ISO-8859-1 的回退
  • 风险与依据

charset 读取失败(如按声明编码解码乱码)时,回退选择需权衡:回退到 UTF-8 是合理默认,因为现代系统、网络、数据库普遍采用 UTF-8,且 UTF-8 严格校验(非法序列易识别),若内容不是 UTF-8 解码会失败可再回退;回退到 ISO-8859-1 是"永不失败"的回退(任意字节都可映射为 Latin-1 字符),但会产生乱码字符(不报错),且无法区分,掩盖真实编码。因此更安全的做法是优先回退 UTF-8(若 UTF-8 解码失败再考虑其他),而非 ISO-8859-1(因为 ISO-8859-1 永不失败但掩盖问题)。最佳实践:明确编码来源,按 BOM/声明/启发式确定,避免盲目回退;回退时记录告警。理解回退 UTF-8(严格可校验)优于 ISO-8859-1(永不失败但掩盖问题)是本题关键。

核心是回退 UTF-8 严格可校验、ISO-8859-1 永不失败但掩盖问题,优先回退 UTF-8 并告警。理解回退依据是本题关键。

#
★★

37. 字符串字面量在 class 文件常量池中 UTF-8 编码后被 javac 改写为 Latin-1 紧凑存储的判定边界

字符串字面量在 class 文件常量池中 UTF-8 编码后,javac 改写为 Latin-1 紧凑存储的判定边界是什么?

  • class 文件常量池的字符串存储
  • Modified UTF-8 与 Latin-1
  • 紧凑字符存储

class 文件常量池中的字符串以 CONSTANT_Utf8 存储,编码固定为 Modified UTF-8(非标准 UTF-8,0 字节编码为 C0 80),常量池本身并不存在 Latin-1 存储选项。所谓"Latin-1 紧凑存储"实际发生在运行时:JEP 254 紧凑字符串(Compact Strings)让 String 内部按 byte[] 存储,若字符串所有字符码点都在 Latin-1(0x00-0xFF)范围内,则用紧凑的 Latin-1 布局(每字符 1 字节);否则用 UTF-16 布局(每字符 2 字节)。判定边界是:字符串是否全部由 Latin-1 可表示字符(0 到 255)组成,即所有字符的码点 ≤ 0xFF。若满足则 Latin-1 紧凑存储(节省内存),否则 UTF-16 存储。理解常量池 Modified UTF-8 与运行时紧凑字符串 Latin-1/UTF-16 判定边界的区别是本题关键。

核心是判定边界为字符码点是否 ≤ 0xFF(Latin-1 可表示),是则紧凑 Latin-1 存储否则 UTF-16。理解判定边界是本题关键。

#
★★

38. 字符集(Charset)与编码器(CharsetEncoder)

字符集(Charset)与编码器(CharsetEncoder)的关系是什么?各自职责如何?

  • Charset 与 CharsetEncoder 的关系
  • 编码器与解码器
  • 职责划分

Charset 是字符集(字符与字节的映射规则),CharsetEncoder 是编码器(将字符编码为字节),CharsetDecoder 是解码器(将字节解码为字符)。Charset 提供了获取编码器/解码器的工厂方法(newEncoder/newDecoder),并定义了字符集名称、别名、是否可编码等。CharsetEncoder 有状态,负责具体的编码过程(处理错误、flush、reset)。关系:Charset 是规则/抽象,Encoder/Decoder 是具体执行器(有状态实例)。使用:Charset.forName("UTF-8").newEncoder() 获取编码器,用编码器编码字符为字节。理解 Charset(规则)与 Encoder/Decoder(执行器)的关系与职责划分是本题关键。

核心是 Charset 是字符集规则,Encoder/Decoder 是有状态执行器,Charset 提供工厂方法。理解关系与职责是本题关键。

#
★★

39. 按字节截断 UTF-8 日志或消息可能切断多字节序列,如何在容量限制下保持文本有效

按字节截断 UTF-8 日志或消息可能切断多字节序列,如何在容量限制下保持文本有效?

  • 按字节截断会切断多字节序列
  • 保持文本有效
  • 截断时处理

UTF-8 是多字节编码,按字节截断可能在多字节字符中间切断(如把 3 字节的中文截成 1 或 2 字节),产生非法/乱码字节。保持文本有效的方法:截断后检查末尾字节,若为多字节序列的起始字节或未完成,则回退到完整字符边界(丢弃不完整的尾字节);或先按字符截断(codePointCount/字素簇)再编码。实现:截断字节后,若最后一个字节是续字节(10xxxxxx),向前回退到该字符的起始字节,确保不切在多字节中间;或使用解码器截断后处理。容量限制下,应在字节级限制但保证字符完整性,必要时回退到安全边界。理解按字节截断的切断风险与回退到完整字符边界的处理是本题关键。

核心是字节截断会切多字节字符,需回退到完整字符边界或按字符截断。理解保持文本有效的方法是本题关键。

#
★★

40. 数据库连接、表、列和会话字符集不一致时,乱码与不可映射错误应如何沿链路定位

数据库连接、表、列和会话字符集不一致时,乱码与不可映射错误应如何沿链路定位?

  • 数据库字符集的多层
  • 乱码与不可映射错误的定位
  • 链路排查

数据库字符集涉及多层:数据库实例、表、列、连接的字符集、JVM 编码、应用层编码。不一致时,写入与读取的字符集不同会产生乱码或不可映射错误(unmappable character)。定位方式:沿链路逐层检查字符集设置——应用层编码(JVM file.encoding、JDBC URL 的 characterEncoding)-> 连接字符集(如 MySQL 的 characterEncoding、Oracle 的 NLS)-> 表/列字符集(如 utf8mb4)-> 数据库实例字符集。排查步骤:确认应用写入的原始编码与 JDBC 参数;查询连接与表/列的字符集(SHOW VARIABLES LIKE 'character_set%');确认数据实际存储的字节(SELECT HEX);定位哪一层发生转换(截断/不可映射)。修复:统一各层字符集(推荐 UTF-8/utf8mb4),修改连接参数、表/列字符集,重建或转换数据。理解沿链路逐层排查字符集不一致是本题关键。

核心是字符集涉及应用/连接/表列/数据库多层,需逐层检查并统一,通过查字符集与 HEX 定位。理解链路排查是本题关键。

#
★★

41. 紧凑字符串在内部选择 LATIN1 或 UTF16 对外部编码有何影响,业务代码为何不应依赖其布局

紧凑字符串在内部选择 LATIN1 或 UTF16 对外部编码有何影响?业务代码为何不应依赖其布局?

  • 紧凑字符串的 LATIN1/UTF16 存储
  • 对外部编码的影响
  • 依赖内部布局的风险

紧凑字符串(JEP 254)是 String 内部优化:若字符串所有字符都可用 Latin-1(码点 ≤ 0xFF)表示,则用 byte[] 以 Latin-1 存储(每字符 1 字节);否则用 byte[] 以 UTF-16 存储(每字符 2 字节)。这减少了内存占用。对外部编码的影响:内部布局不影响 getBytes(Charset) 等外部编码结果(外部编码由字符集决定),但影响 String 内部存储与某些操作(如 getBytes 的 intrinsic 优化)。业务代码不应依赖内部布局的原因:内部存储是 JDK 实现细节,可能变化(如未来 JEP 调整),依赖 LATIN1/UTF16 布局会导致代码在不同 JDK 版本行为异常;且业务应通过 String API(length、codePointAt、getBytes 指定 Charset)处理,而非假设内部字节布局。理解紧凑字符串布局是内部优化、外部编码不受影响、业务不应依赖内部布局是本题关键。

核心是紧凑字符串内部 LATIN1/UTF16 是 JVM 优化、外部编码由字符集决定,业务不应依赖内部布局。理解其影响与风险是本题关键。

#
★★

42. 网络 I/O 的字符集约定

网络 I/O 的字符集约定是什么?应如何约定与处理?

  • 网络 I/O 的字符集约定
  • 协议级字符集声明
  • 编解码处理

网络 I/O 的字符集约定是:在协议层明确声明的字符集(如 HTTP 的 Content-Type charset、JSON 的 UTF-8、XML 的 encoding 声明),发送方与接收方按约定编码/解码。常见约定:文本协议默认 UTF-8(HTTP/JSON、XML、WebSocket 等);二进制协议通过长度前缀 + 明确字符集。处理方式:发送方按约定字符集编码(如 UTF-8),接收方先按协议声明解码,解码失败时回退并告警。应避免依赖默认编码(不确定性),统一约定 UTF-8 以减少混乱。网络 I/O 的字符集约定核心是"协议层明确 + 收发一致 + 统一 UTF-8"。理解网络 I/O 需在协议层约定字符集并保证收发一致是本题关键。

核心是网络 I/O 通过协议声明字符集(如 Content-Type charset),收发一致并统一 UTF-8。理解约定与处理是本题关键。

#
★★

43. 跨语言排序与比较为何不能只看 Unicode 码点,Collator 的强度和规范化应怎样配置

跨语言排序与比较为何不能只看 Unicode 码点?Collator 的强度和规范化应怎样配置?

  • 码点排序的局限
  • Collator 的强度
  • 规范化配置

跨语言排序与比较不能只看 Unicode 码点,因为码点顺序与语言感知排序不符(如中文按拼音/笔画、拉丁字符大小写、重音通常忽略),且等价字符(如 é 的不同表示)需规范化。Collator 提供语言感知的排序与比较,其强度(Strength)控制比较的严格程度:PRIMARY(只比较根本字符,忽略大小写/重音)、SECONDARY(比较重音)、TERTIARY(比较大小写)、IDENTICAL(完全相等)。配置:根据需求选择强度(如搜索忽略大小写用 SECONDARY/TERTIARY);配合规范化(Normalizer.normalize)统一等价表示;用 Locale 指定语言规则。跨语言场景应使用 Collator 而非 String.compareTo(码点比较)。理解码点排序的局限与 Collator 强度/规范化配置是本题关键。

核心是码点排序不具语言感知,应用 Collator 并按需求配置强度与规范化。理解局限与配置是本题关键。

#
★★

44. CharsetEncoder 的 replacement 与 unmappableCharacterAction 在 JDK 25 虚拟线程下的内存序如何保证

CharsetEncoder 的 replacement 与 unmappableCharacterAction 在 JDK 25 虚拟线程下的内存序如何保证?

  • replacement 与 unmappableCharacterAction
  • 内存序与可见性
  • 虚拟线程下的并发

CharsetEncoder 的 replacement(替换字符)与 unmappableCharacterAction(不可映射字符处理策略)是编码器的配置属性。CharsetEncoder 本身不是线程安全的(有状态),通常由单个线程使用或在 ThreadLocal 中隔离。在 JDK 25 虚拟线程下,若多个虚拟线程共享同一 CharsetEncoder,需外部同步保证内存序与可见性(如 synchronized、volatile 或专用线程)。但最佳实践仍是每个虚拟线程独立编码器(ThreadLocal)或使用池化,避免共享。内存序保证:虚拟线程共享载体线程池,但共享可变状态(如编码器属性)仍需 JMM 的可见性保证(synchronized/volatile)。理解 CharsetEncoder 非线程安全、虚拟线程下仍需同步或隔离编码器、内存序通过锁保证是本题关键。

核心是 CharsetEncoder 非线程安全,虚拟线程下共享需外部同步保证内存序,最佳实践是 ThreadLocal 隔离。理解内存序与并发是本题关键。

#
★★

45. 无 BOM 文本的编码自动检测方法(启发式统计/ICU CharsetDetector)及其误判风险

无 BOM 文本的编码自动检测方法有哪些?其误判风险是什么?

  • 无 BOM 的编码检测
  • 启发式统计与 ICU CharsetDetector
  • 误判风险

无 BOM 文本的编码检测方法:启发式统计(分析字节序列的合法性与频率,如 UTF-8 的字节模式、常见字符分布)、ICU CharsetDetector(国际化的字符集检测库,综合多种统计与语言模型)、BOM 检测(若存在 BOM 则明确)。误判风险:检测基于统计,非确定性,可能误判(如 UTF-8 与 GBK 的字节序列都合法时,可能误判);短文本或特殊内容(如全是 ASCII)难以区分;误判会导致乱码或数据损坏。缓解:检测结果作为参考,结合业务约定(默认 UTF-8)与校验(解码后是否有非法序列);对关键数据明确编码。理解无 BOM 检测方法(启发式/ICU)与误判风险(统计非确定)是本题关键。

核心是检测基于启发式统计/ICU 非确定,存在误判风险,需结合业务约定与校验。理解方法与风险是本题关键。

#

46. JDK 25 中 Properties 配置文件默认 ISO-8859-1 与 loadFromXML 的 UTF-8 编码边界

JDK 25 中 Properties 配置文件默认 ISO-8859-1 与 loadFromXML 的 UTF-8 编码边界是什么?

  • Properties 默认 ISO-8859-1
  • loadFromXML 的 UTF-8
  • 编码边界

Properties.load(InputStream) 默认按 ISO-8859-1(Latin-1)读取 .properties 文件,因此非 ASCII 字符需用 \uXXXX 转义;Properties.loadFromXML(InputStream) 读取 XML 格式的属性文件,按 UTF-8 编码(XML 声明 encoding="UTF-8"),可直接写中文。编码边界:.properties 用 ISO-8859-1(或转义),.xml 用 UTF-8。分界:若需支持中文直接书写,用 loadFromXML(UTF-8)或 load(Reader) 指定 UTF-8;若用 .properties 的 ISO-8859-1,需转义或改用现代配置。理解 Properties 默认 ISO-8859-1 与 loadFromXML 的 UTF-8 边界是本题关键。

核心是 .properties 默认 ISO-8859-1 需转义,.xml(loadFromXML) 用 UTF-8 可直接写中文。理解编码边界是本题关键。

#

47. 紧凑字符串(JEP 254)与 JDK 25 对 String.getBytes(UTF_8) 的 intrinsic 优化

紧凑字符串(JEP 254)与 JDK 25 对 String.getBytes(UTF_8) 的 intrinsic 优化有什么联系?

  • 紧凑字符串的存储
  • getBytes(UTF_8) 的 intrinsic 优化
  • 优化关联

紧凑字符串(JEP 254)让 String 内部按 Latin-1 或 UTF-16 紧凑存储,减少了内存。JDK 对 String.getBytes(UTF_8) 等常用操作做了 intrinsic 优化(JIT 生成高效的汇编代码,利用 CPU 的 SIMD 指令批量转换),提高编码吞吐。联系:紧凑字符串的存储布局(Latin-1 用单字节)使得 getBytes(UTF_8) 对 Latin-1 字符串的编码更简单(可直接映射),intrinsic 优化受益于整洁的布局;对 UTF-16 存储的字符串,intrinsic 仍用 SIMD 加速多字节转换。JDK 25 的 intrinsic 优化针对大字符串(如长字符串、缓冲)的 UTF-8 编码,利用 SIMD 提升吞吐。理解紧凑字符串布局与 getBytes(UTF_8) intrinsic(SIMD)优化的关联是本题关键。

核心是紧凑字符串布局简化 Latin-1 编码,getBytes(UTF_8) intrinsic 用 SIMD 加速,二者共同提升编码性能。理解关联是本题关键。

#

48. java.util.Base64 的模块归属与 Native Image 体积优化边界

java.util.Base64 的模块归属与 GraalVM Native Image 体积优化边界是什么?

  • Base64 的模块归属
  • Native Image 的体积优化
  • 边界

java.util.Base64 位于 java.base 模块(java.util 包),是 JDK 内置的 Base64 编码/解码实现,支持 basic、URL-safe、MIME 三种变体。在 GraalVM Native Image 中,Base64 属于 JDK 标准库,可被静态分析并纳入镜像;其实现(如查表、intrinsic 优化)在 Native Image 中可能被优化或采用不同实现。体积优化边界:Base64 作为 java.base 的类,Native Image 默认会包含所需的代码;若应用中大量使用 Base64,可考虑其 intrinsic 与查表是否被内联;对于精简体积,可只引入所需变体(但标准库通常整体包含)。理解 Base64 在 java.base 且 Native Image 中作为标准库类被分析纳入、体积优化受限于标准库包含是本题关键。

核心是 Base64 在 java.base,Native Image 默认纳入标准库实现,体积优化边界受标准库包含影响。理解模块归属与边界是本题关键。

#

49. JDK 25 引入的 JEP 484 Class-File API 在解析 class 文件常量池字符串时是否仍使用 Modified UTF-8

JDK 25 引入的 JEP 484 Class-File API 在解析 class 文件常量池字符串时是否仍使用 Modified UTF-8?

  • JEP 484 Class-File API
  • 常量池字符串编码
  • Modified UTF-8

JEP 484 是 JDK 22+ 引入的标准 Class-File API,用于解析、生成和转换 class 文件,替代内部 sun.misc 的 class 解析。class 文件常量池中的 CONSTANT_Utf8 字符串以 Modified UTF-8 编码(非标准 UTF-8,0 字节编码为 C0 80,补充平面用代理对)。JEP 484 的 Class-File API 在读取常量池字符串时,按规范仍使用 Modified UTF-8 解码(因为这是 class 文件格式的规定),但 API 对外暴露的是 Java String(解码后的字符)。因此解析时仍涉及 Modified UTF-8 的读取,但 API 层返回标准 String。理解 JEP 484 Class-File API 解析常量池时仍按 Modified UTF-8 存储/解码、对外暴露 String 是本题关键。

核心是 class 常量池字符串用 Modified UTF-8,JEP 484 API 读取时仍按此编码但对外暴露 String。理解编码与 API 是本题关键。

#

50. JEP 400 与 UTF-8 默认文件编码的关系在 JDK 25 中是否已正式落地

JEP 400 与 UTF-8 默认文件编码的关系在 JDK 25 中是否已正式落地?

  • JEP 400 默认 UTF-8
  • JDK 25 的落地状态
  • file.encoding 默认值

JEP 400(UTF-8 by Default)在 JDK 18 正式落地,将默认字符集统一为 UTF-8,不再依赖操作系统区域设置(LANG/LC_ALL)。在 JDK 25 中,这一特性已正式落地并持续生效:默认 file.encoding 为 UTF-8,除非显式通过 -Dfile.encoding 覆盖。因此 JDK 25 中默认文件编码为 UTF-8,String.getBytes()(无参数)、Files.readString 等默认使用 UTF-8。JEP 400 的落地使跨平台行为一致,消除了旧版依赖系统编码导致的不一致问题。理解 JEP 400 在 JDK 18 落地、JDK 25 持续生效默认 UTF-8 是本题关键。

核心是 JEP 400 在 JDK 18 落地,JDK 25 默认 UTF-8 持续生效,除非显式覆盖。理解落地状态是本题关键。

#

51. JFR 中与字符集相关的事件(如 jdk.Charset 事件)

JFR 中与字符集相关的事件(如 jdk.Charset 事件)是什么?如何用于分析?

  • JFR 的字符集事件
  • jdk.Charset 事件
  • 性能分析

JFR 提供 jdk.Charset 事件(jdk.Charset、jdk.CharsetConverter 等),记录字符集转换的相关信息。例如 jdk.Charset 事件在字符集转换操作发生时记录(编码/解码),可用于分析字符集转换的频率、耗时、转换的字符量,帮助定位字符集转换的性能瓶颈(如大量字符串编码/解码)。使用方式:开启 JFR 录制,分析 jdk.Charset 事件,观察字符集转换的热点与开销。这对优化大量 I/O 与文本处理的场景有价值。理解 JFR 的 jdk.Charset 事件记录字符集转换信息、用于分析转换性能是本题关键。

核心是 JFR 的 jdk.Charset 事件记录字符集转换,用于分析编码/解码性能瓶颈。理解事件与用途是本题关键。

#

52. UTF-8 编码 intrinsic 优化(JDK 25)对大字符串编码吞吐的影响

JDK 25 的 UTF-8 编码 intrinsic 优化对大字符串编码吞吐的影响是什么?

  • UTF-8 编码 intrinsic
  • SIMD 优化
  • 大字符串吞吐

JDK 的 UTF-8 编码 intrinsic 优化(JIT 生成 SIMD 汇编,利用 CPU 的 AVX/SSE 指令批量编码)显著提升了大字符串的编码吞吐。对于大字符串(如长文本、大缓冲),intrinsic 优化通过向量化同时处理多个字符,减少循环开销与分支,大幅提高 getBytes(UTF_8) 的吞吐。JDK 25 中该优化持续改进,对大字符串编码吞吐有显著提升。适用:大字符串、批量编码场景;小字符串优化收益有限(开销摊销)。理解 UTF-8 intrinsic 用 SIMD 向量化提升大字符串编码吞吐是本题关键。

核心是 UTF-8 intrinsic 用 SIMD 向量化批量编码,显著提升大字符串吞吐,小字符串收益有限。理解优化影响是本题关键。

#

53. Base64 的 URL-safe 与 MIME 变体在 JWT 与邮件场景的差异

Base64 的 URL-safe 与 MIME 变体在 JWT 与邮件场景的差异是什么?

  • Base64 的 basic/URL-safe/MIME 变体
  • JWT 与邮件场景
  • 差异

java.util.Base64 提供三种变体:basic(标准,用 + / 和 = 填充)、URL-safe(用 - 和 _ 替代 + 和 /,适合 URL 与 JWT)、MIME(按 RFC 2045 每 76 字符插入 CRLF 换行,不附带 MIME 头——头由邮件协议层添加,适合邮件正文)。JWT 使用 URL-safe 变体(无 padding 可选),因为 JWT 的 token 在 URL、header 中传输,+ / = 会破坏 URL 语义,用 - _ 且通常去掉 = 填充。邮件(MIME)使用 MIME 变体,按 76 字符插入换行,兼容 MIME 规范。差异:字符集(+ / 与 - _)、填充(= 是否保留)、换行(MIME 分块)。理解三种变体在 JWT(URL-safe)与邮件(MIME)场景的使用差异是本题关键。

核心是 URL-safe 用 - _ 适合 JWT/URL,MIME 按 76 字符换行适合邮件,字符/填充/换行有差异。理解差异是本题关键。