java中char类型固定占2字节,统一以utf-16编码单元存储,与字符内容无关;取值范围0–65535,支持bmp内字符单char表示,超bmp需代理对;string优化不影响char本身内存布局。

Java 中 char 类型固定占 2 个字节(16 位),它不是按字符内容动态变长,而是统一以 UTF-16 编码单元形式在内存中存储。这个大小与你存的是 'a' 还是 '汉' 无关,也与文件或网络传输时的编码无关——那是 String.getBytes() 的事,不是 char 本身的内存结构。
char 的内存大小是硬性规定,不随内容变化
Java 语言规范明确要求:每个 char 占用 2 字节,且为无符号类型,取值范围是 0 到 65535(即 Unicode 基本多语言平面 BMP 内的码点)。无论你写:
-
char c1 = 'A';—— ASCII 字符,高位字节为 0x00,低位为 0x41 -
char c2 = '中';—— Unicode 码点 U+6C49,直接存为 0x6C49(大端序:低地址存 0x6C,高地址存 0x49)
它们在栈或数组中都占据连续的 2 个字节空间。你可以用 Unsafe 或序列化工具验证,但更简单的是:Character.BYTES 恒等于 2。
UTF-16 是 char 的底层编码逻辑
Java 选择 UTF-16,是因为它能用单个 char 表示 BMP 范围内全部字符(含常用汉字、拉丁、希腊、阿拉伯等),而无需查表或解析变长序列。关键点:
- 绝大多数字符(如英文字母、数字、常用汉字)→ 单个 char(2 字节)
- 超出 BMP 的字符(如部分 emoji、古文字)→ 需要两个 char 组成代理对(surrogate pair),共占 4 字节才能表示一个 Unicode 码点
- char 本身不“知道”自己是不是代理对的一部分;判断需配合
Character.isHighSurrogate()等方法
别把 char 和 String.getBytes() 混为一谈
这是最常踩的坑:char 占 2 字节 ≠ 字符串转字节数组后也是 2×字符数。因为:
-
String s = "中";→s.length()是 1(1 个 char),但s.getBytes("UTF-8").length是 3(UTF-8 下汉字占 3 字节) -
s.getBytes("ISO-8859-1")会抛异常(不支持中文),而s.getBytes("GBK")返回 2 字节 -
s.getBytes("UTF-16")通常返回 4 字节(含 BOM 头),实际字符数据仍是 2 字节,但编码格式加了额外信息
记住:char 是内存中的基本单元;getBytes() 是按指定编码规则做的“翻译”,输出的是面向 I/O 的字节流,不是 char 的镜像。
Java 9+ 的字符串优化不影响 char 本身
JDK 9 引入紧凑字符串(Compact Strings),对只含 Latin-1 字符(U+0000–U+00FF)的 String,内部改用 byte[] 存储,每个字符仅占 1 字节——但这只是 String 对象的实现细节优化。
- 你声明
char c = 'z';,它依然占 2 字节 - 你调用
"abc".toCharArray(),返回的 char[] 每个元素还是 2 字节 - String 的内部优化不改变 char 类型语义,也不影响其作为参数、变量或数组元素的内存布局
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











