java中char是16位无符号整数,采用utf-16编码表示unicode码点,bmp字符占2字节、增补字符需两个char组成代理对;string内部逻辑基于utf-16,length()返回char数而非真实字符数;byte[]与string互转必须显式指定standardcharsets编码,避免依赖系统默认值导致乱码。

Java 中字符存储和编码转换的核心在于理解 char、String、byte[] 三者之间的关系,以及 JVM 默认编码与实际字节流编码的差异。不搞清这点,读写文件乱码、HTTP 请求参数错乱、数据库存取异常等问题就会反复出现。
字符在 Java 里怎么存?
Java 的 char 类型是 16 位无符号整数(0–65535),采用 UTF-16 编码表示 Unicode 码点。一个 char 可以表示基本多文种平面(BMP)内的字符,但无法单独表示增补字符(如 emoji 或部分汉字),后者需用两个 char(代理对)组合表达。
-
String内部由char[](Java 8)或byte[] + coder(Java 9+)实现,逻辑上仍是基于 UTF-16 的字符序列 -
String.length()返回的是char个数,不是真实 Unicode 字符数(遇到代理对会算作 2 个) - 要获取真正的 Unicode 字符数,用
string.codePointCount(0, string.length())
byte[] 和 String 怎么安全互转?
转换必须显式指定编码名称,不能依赖平台默认。JVM 启动时的 file.encoding 只影响部分 API(如 new Scanner(System.in)),不代表所有操作都按此编码。
- 字符串 → 字节数组:
"你好".getBytes(StandardCharsets.UTF_8)(推荐用StandardCharsets枚举,类型安全) - 字节数组 → 字符串:
new String(bytes, StandardCharsets.UTF_8) - 避免使用
getBytes()或new String(bytes)无参构造,它们调用系统默认编码,跨环境极易出错
文件读写中的编码陷阱
用 FileReader/FileWriter 时,默认使用系统编码,且无法指定;应改用 InputStreamReader/OutputStreamWriter 显式传入 Charset。
- 读文件:用
Files.newBufferedReader(path, StandardCharsets.UTF_8) - 写文件:用
Files.newBufferedWriter(path, StandardCharsets.UTF_8) - 旧 API 如
FileInputStream需配合InputStreamReader手动包装,否则字节直接转 char 会按平台编码解析,导致乱码
网络与外部系统交互的编码处理
HTTP 请求头、数据库连接 URL、JSON 解析库等都有各自默认编码,需统一协调。
- HTTP 响应体:Spring Boot 中设置
spring.http.encoding.charset=UTF-8;手动解析时,从响应头Content-Type: text/html; charset=utf-8提取编码,并用该 Charset 解码 body 字节数组 - JDBC 连接:MySQL URL 加
?characterEncoding=utf8mb4&useUnicode=true,确保支持 4 字节 UTF-8 字符(如 ?) - JSON 库(如 Jackson):默认用 UTF-8,但若输入流未标记编码,需在
ObjectMapper.readValue(InputStream, ...)前确认流已按正确编码解码
编码问题本质是字节与字符映射关系的错位。只要每一步转换都明确编码意图,不依赖隐式默认值,就能避开绝大多数坑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











