这是一个非常经典且重要的问题,但答案并不是一个固定的数字。一个 Java 字符串(String)所占用的字节数取决于三个核心因素:

- 字符编码:这是最关键的因素,不同的编码方式会用不同数量的字节来表示同一个字符。
- :字符串中包含的字符本身,不同字符(如英文字母 'A' 和中文字 '中')在同一个编码下占用的字节数可能不同。
- JVM 实现和内存布局:对象头、对齐填充等也会占用额外的内存。
下面我们详细分解这三个因素,并给出计算方法和示例。
核心因素:字符编码
Java 源代码中的字符串是 Unicode 字符,但在内存中或写入文件/网络时,必须被编码成字节序列,最常见的编码有:
| 编码方式 | 描述 | 英文字母 (如 'A') | 中文字符 (如 '中') | Emoji (如 '😊') |
|---|---|---|---|---|
| ISO-8859-1 (Latin-1) | 单字节编码,不支持中文 | 1 字节 | 1 字节 (会乱码,无法表示) | 1 字节 (会乱码) |
| GBK / GB2312 | 中国国家标准编码,支持中文 | 1 字节 | 2 字节 | 通常不支持,会乱码 |
| UTF-16 | Java 内部默认使用的编码,固定 2 或 4 字节 | 2 字节 | 2 字节 | 4 字节 (辅助平面字符) |
| UTF-8 | 目前互联网上最流行的变长编码,兼容 ASCII | 1 字节 | 3 字节 | 4 字节 |
在讨论字符串字节大小时,必须明确是在哪种编码下。
字符串中包含的字符类型决定了在特定编码下的字节数。

- ASCII 字符:在
UTF-8和GBK下通常只占 1 字节。 - 常用中文字符:在
GBK下占 2 字节,在UTF-8下占 3 字节。 - Emoji 或生僻汉字:在
UTF-8下可能占 4 字节。
JVM 对象内存开销
一个 Java String 对象不仅仅是字符数组,它还有一些额外的固定开销。
在主流的 64 位 JVM(使用压缩指针 -XX:+UseCompressedOops 的情况下)中,一个普通对象的内存布局大致如下:
- 对象头:通常是 12 字节(用于存储对象的元数据、哈希码、锁信息等)。
- 引用字段:指向
char[]数组的引用本身占 4 字节(因为压缩指针)。 - 实例数据:对于
String,private final char[] value;这个数组本身。 - 对齐填充:JVM 要求对象的大小必须是 8 字节的倍数,如果不足则需要填充。
一个空字符串 至少也会占用 12 (对象头) + 4 (value引用) = 16 字节,并且已经对齐,无需填充。
如何计算一个字符串的字节数?
我们可以通过两种方式来计算:
理论计算(推荐用于理解)
总字节数 = 对象头 + value引用 + 数组长度 + 字符内容字节数 + 数组对齐填充
让我们用一个例子来计算:String str = "ABC中";
-
确定编码和字符字节数:
- 'A', 'B', 'C' 是 ASCII 字符,在
UTF-8下各占 1 字节。 - '中' 是中文字符,在
UTF-8下占 3 字节。 - 字节数 = 1 + 1 + 1 + 3 = 6 字节。
- 'A', 'B', 'C' 是 ASCII 字符,在
-
计算
char[]数组的内存占用:- 数组对象头:12 字节。
- 数组长度 (
int类型):4 字节。 - 数组数据:
char[]本身,在 Java 中,char类型是 2 字节的,char[4]数组的数据部分占4 * 2 = 8字节。 char[]数组总大小 = 12 (头) + 4 (长度) + 8 (数据) = 24 字节,这个大小已经是 8 的倍数,无需对齐填充。
-
计算
String对象本身的内存占用:String对象头:12 字节。value引用:4 字节。String对象本身大小 = 12 + 4 = 16 字节,这个大小也已经是 8 的倍数,无需对齐填充。
-
String对象本身占用 16 字节。- 它内部的
char[]数组占用 24 字节。 - 整个
String对象在堆上总共占用 16 + 24 = 40 字节。
注意:这里的 40 字节是 JVM 对象的内存占用,它包含了
char[]中未编码的 Unicode 字符,如果你想问这个字符串在UTF-8编码下会生成多少个字节,那么答案是 6 字节。
代码实践(推荐用于验证)
你可以通过 getBytes() 方法来获取特定编码下的字节数。
public class StringSizeExample {
public static void main(String[] args) {
String str = "ABC中";
// 1. 获取不同编码下的字节数
System.out.println("--- 字符串内容在不同编码下的字节数 ---");
try {
System.out.println("UTF-8: " + str.getBytes("UTF-8").length + " 字节"); // 1+1+1+3 = 6
System.out.println("GBK: " + str.getBytes("GBK").length + " 字节"); // 1+1+1+2 = 5
System.out.println("UTF-16: " + str.getBytes("UTF-16").length + " 字节"); // 2+2+2+2 = 8 (注意UTF-16有BOM头,可能为10)
System.out.println("ISO-8859-1: " + str.getBytes("ISO-8859-1").length + " 字节"); // 1+1+1+1 = 4 (中文会乱码)
} catch (Exception e) {
e.printStackTrace();
}
// 2. 估算JVM中对象的内存占用 (使用工具类)
// 注意:这需要引入第三方库,如 org.openjdk.jol
// 这里只展示概念,不直接运行
/*
import org.openjdk.jol.vm.VM;
System.out.println("\n--- JVM中对象的内存布局 (使用JOL工具) ---");
System.out.println(VM.current().details(str));
*/
// JOL 输出会类似这样,证实我们的理论计算:
// java.lang.String object internals:
// OFFSET SIZE TYPE DESCRIPTION VALUE
// 0 12 (object header) N/A
// 12 4 char[] String.value N/A
// 16 4 int String.hash N/A
// 20 1 byte String.coder N/A
// 21 1 byte String.flags N/A
// 24 4 (loss due to the next object alignment)
// Instance size: 24 bytes
// Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
// 注意:JOL 的结果可能因JVM版本和参数而异,但总大小通常在 40-48 字节左右。
}
}
| 问题场景 | 答案 | 示例 ("ABC中") |
|---|---|---|
| 在 UTF-8 编码下,字符串有多长? | 等于所有字符按 UTF-8 编码后的字节数之和。 | 6 字节 |
| 在 GBK 编码下,字符串有多长? | 等于所有字符按 GBK 编码后的字节数之和。 | 5 字节 |
在 JVM 中,一个 String 对象占用多少内存? |
这是一个固定开销(约 16-24 字节)加上其内部 char[] 数组的内存(约 24 字节起),总计通常在 40-48 字节 左右,与内容无关。 |
约 40 字节 |
当别人问 "Java String 几个字节" 时,最严谨的回答是:“这取决于编码方式和字符串内容,在 UTF-8 编码下,一个英文字符占 1 字节,一个中文字符通常占 3 字节,JVM 对象本身还有额外的固定内存开销。”
