这是一个非常经典且重要的问题,答案比“固定几个字节”要复杂一些,答案是:

在 Java 中,一个 char 类型在内存中永远占用 2 个字节。
但这背后涉及到了 Java 的设计哲学和字符编码,下面我们来详细解释。
核心答案:char 是 2 字节 (UTF-16)
在 Java 的虚拟机规范中,char 类型被定义为 16 位(bit)的 Unicode 字符,因为 1 字节 = 8 位,
char 在内存中固定占用 2 个字节。

这个 char 类型使用的是 UTF-16 编码方案,UTF-16 是一种变长编码,但对于基本多语言平面(BMP)中的字符(包括世界上绝大多数常用的字符,如所有汉字、英文字母、拉丁字母等),UTF-16 就用 2 个字节(16位)来表示。
代码示例
public class CharSize {
public static void main(String[] args) {
char a = 'A'; // 英文字符
char zh = '中'; // 中文字符
// 使用 Character 类的 SIZE 常量
System.out.println("A char occupies: " + Character.SIZE + " bits"); // 输出: 16 bits
System.out.println("A char occupies: " + Character.BYTES + " bytes"); // 输出: 2 bytes
// 在内存中,无论是什么字符,都占2个字节
System.out.println("The character 'A' is stored in 2 bytes.");
System.out.println("The character '中' is stored in 2 bytes.");
}
}
深入理解:为什么是 UTF-16?
Java 诞生于 1990 年代中期,当时 Unicode 标准正处于从 16 位向 32 位扩展的过渡期,设计者选择了 UTF-16,因为它:
- 能够用 16 位覆盖当时已知的所有字符(基本多语言平面)。
- 对于英文字符,UTF-16 和 ASCII 一样,只需 2 个字节,比 UTF-8 的 1 个字节稍大,但处理起来更简单(定长)。
- 对于 BMP 之外的字符(如一些生僻的古文字或特殊符号),UTF-16 使用“代理对”(Surrogate Pair)机制,即用两个
char(4个字节)来表示一个字符,这在 Java 中是透明的,你仍然操作的是char类型。
常见的误区与澄清
“一个中文字符等于两个英文字符,所以一个中文字符占 2 个字节,一个英文字符占 1 个字节。”
这是错误的。 这个说法混淆了 字符的显示宽度 和 字符的存储/编码大小。
- 显示宽度:在某些等宽字体(如终端、代码编辑器)中,一个中文字符确实占据两个英文字符的宽度,这是一种显示特性。
- 存储大小:在 Java 的
char类型中,无论 'A' 还是 '中',都严格占用 2 个字节。
“Java 字符串是由 char 组成的,所以一个字符串的字节数 = 字符数 × 2。”
这通常是正确的,但有例外。
一个 String 对象在内存中是由 char 数组构成的,所以对于不包含代理对的字符串,其字节数确实是 length() * 2。
如果字符串包含了 BMP 之外的字符(,这是一个生僻的汉字),Java 内部会用两个 char 来表示它。String.length() 会返回 2,但这个字符在逻辑上只算 1 个。
// 这个字符 '𠮷' (U+20BB7) 在 BMP 之外
String s = "𠮷";
// String.length() 返回的是 char 数组的长度,这里是 2
System.out.println(s.length()); // 输出: 2
// 但它实际上只代表 1 个 Unicode 码点
System.out.println(s.codePointCount(0, s.length())); // 输出: 1
// 如果你想知道字符串在 UTF-16 编码下的确切字节数
byte[] utf16Bytes = s.getBytes(StandardCharsets.UTF_16);
System.out.println("UTF-16 byte length: " + utf16Bytes.length); // 输出: 4 (因为有 BOM 头 + 2个char)
实际应用:如何计算字符串的字节数?
如果你想知道一个 String 在特定编码(如 UTF-8)下占用的字节数,绝对不能简单地用 length() * 2,必须使用 String.getBytes() 方法。
import java.nio.charset.StandardCharsets;
public class StringByteSize {
public static void main(String[] args) {
String str = "Hello 你好";
// 1. 错误的方法:不能直接 length() * 2
// 这只适用于纯 BMP 字符且不考虑编码的情况
// System.out.println("Wrong size: " + str.length() * 2); // 14 bytes
// 2. 正确的方法:使用 getBytes() 指定编码
// UTF-8 编码下,英文字符占1字节,中文字符占3字节
byte[] utf8Bytes = str.getBytes(StandardCharsets.UTF_8);
System.out.println("UTF-8 byte length: " + utf8Bytes.length); // 输出: 11 (5*1 + 2*3 = 11)
// UTF-16 编码下,英文字符和中文字符都占2字节
byte[] utf16Bytes = str.getBytes(StandardCharsets.UTF_16);
// 注意:UTF-16 通常会包含一个 BOM (Byte Order Mark) 头,占用2字节
// 所以总长度是 2 (BOM) + 7 (字符数) * 2 = 16
System.out.println("UTF-16 byte length: " + utf16Bytes.length); // 输出: 16
// GBK 编码下,英文字符占1字节,中文字符占2字节
byte[] gbkBytes = str.getBytes("GBK");
System.out.println("GBK byte length: " + gbkBytes.length); // 输出: 9 (5*1 + 2*2 = 9)
}
}
| 问题 | 答案 | 解释 |
|---|---|---|
一个 char 占几个字节? |
2 个字节 | Java 虚拟机规范规定 char 是 16 位,固定占用 2 字节,使用 UTF-16 编码。 |
| 一个中文字符占几个字节? | 在 char 中是 2 个字节 |
存储时,和英文字符一样,都占 2 字节。 |
| 如何计算字符串的字节数? | 使用 String.getBytes(编码) |
字符串的字节数取决于其编码方式(UTF-8, GBK 等),不能简单地用字符数乘以一个固定值。 |
char 和 String 的关系? |
String 是 char[] 的封装 |
String 的底层是 char 数组,但处理字符数量时要注意代理对的情况。 |
记住这个核心区别:char 是 JVM 内部的固定大小类型(2字节),而字符的存储和传输则取决于具体的编码(如 UTF-8, GBK)。
