杰瑞科技汇

Java String几个字?长度或特性?

这是一个非常经典的问题,但它的答案取决于你问的是哪个“Java String”,我会从三个层面来详细解释:

Java String几个字?长度或特性?-图1
(图片来源网络,侵删)

从“类”的角度看:java.lang.String 类本身有多大?

如果你问的是 String 这个类对象在内存中占用多少字节,答案是:它的大小是固定的,通常是 16 字节(在 64 位 JVM 中,开启压缩指针的情况下)

这 16 字节由以下部分组成(以常见的 HotSpot JVM 为例):

部分 大小 (字节) 描述
Mark Word 8 对象的“标记”,用于存储哈希码、锁状态、分代年龄等,这是所有 Java 对象都有的部分。
Klass Pointer 4 (或 8) 指向该对象所属的类元数据的指针,在 64 位 JVM 且开启 UseCompressedClassPointers (默认开启) 时为 4 字节,否则为 8 字节。
长度 (length) 4 一个 int 值,存储字符串的字符数量。
对齐填充 (Padding) 4 为了让对象的总大小是 8 字节的倍数(64 位系统上对象内存按 8 字节对齐),需要填充 4 字节。
总计 16

关键点:

  • String 对象本身不存储字符数据!它只存储字符的数量和指向字符数组的指针
  • 字符数据("你好" 这两个汉字)存储在另一个叫做 char[] 的数组对象中。

从“实例”的角度看:一个具体的字符串变量占多少内存?

这取决于字符串的内容长度,内存消耗分为两部分:

Java String几个字?长度或特性?-图2
(图片来源网络,侵删)

a) String 对象本身 (固定部分)

如上所述,通常是 16 字节

b) 底层的 char[] 数组对象 (可变部分)

这个数组对象的大小也由固定部分和可变部分组成。

部分 大小 (字节) 描述
Mark Word 8 数组对象的标记。
Klass Pointer 4 指向 char[] 类型的指针。
长度 (length) 4 一个 int 值,存储数组的长度。
数据区 (Data) 字符数 * 2 每个字符在 Java 中是 2 字节的 UTF-16 编码。
对齐填充 (Padding) 0 (如果总大小刚好是 8 的倍数则不需要)
总计 *16 + 字符数 2**

一个完整的字符串实例的总内存占用 ≈ String对象大小 + char[]数组对象大小

总大小 ≈ 16 + (16 + 字符数 2) = 32 + 字符数 2


举例说明

假设我们有以下 Java 代码:

String str = "你好"; // 两个汉字

我们来计算 str 这个变量在内存中占用的总空间:

  1. String 对象部分 (固定)

    • Mark Word: 8 字节
    • Klass Pointer: 4 字节
    • length: 4 字节 (值为 2)
    • Padding: 4 字节
    • 小计: 16 字节
  2. char[] 数组对象部分 (可变)

    • Mark Word: 8 字节
    • Klass Pointer: 4 字节
    • length: 4 字节 (值为 2)
    • 数据区: 2 个字符 * 2 字节/字符 = 4 字节
    • 小计: 8 + 4 + 4 + 4 = 20 字节
  3. 总计

    • String 对象 + char[] 数组对象 = 16 + 20 = 36 字节

变量 str "你好" 在内存中总共占用了 36 字节


从“字符串字面量”的角度看:"abc" 有几个字?

如果你问的是 String 字面量(代码中直接写的字符串),"abc"

  • "abc" 这三个字符本身:每个字符在 Java 中是 2 字节,3 * 2 = 6 字节。
  • String 对象:如上所述,它包含一个指向字符数组的指针和长度信息,对象本身固定为 16 字节(在 64 位 JVM 中)。

重要知识点:字符串常量池 Java 为了优化性能和内存,有一个叫做字符串常量池 的区域,当你写 "abc" 时,JVM 会在编译期或类加载时,在常量池中创建一个 String 对象,如果代码中其他地方也出现了 "abc",它们都会引用常量池中同一个对象,而不会重复创建。

String s1 = "abc";String s2 = "abc"; 中,s1s2 指向的是内存中同一个 String 对象。


问题 答案 解释
String 类本身有多大? 16 字节 (64位JVM, 压缩指针) 这是 String 对象头和 length 字段的总和,不包含字符数据。
一个字符串变量占多少内存? *32 + (字符数 2) 字节** String 对象 (16字节) 和 char[] 数组对象 (16 + 字符数*2 字节) 组成。
"你好" 占多少内存? 36 字节 String对象(16) + char[]数组(20) = 36 字节。
"abc" 这几个字? 字符部分 6 字节 字符 'a', 'b', 'c' 每个占 2 字节,但完整的 String 对象占更多内存。

如何准确测量? 如果你想精确测量一个字符串占用的内存,不要自己计算,使用专业的工具:

  • JOL (Java Object Layout): 轻量级,可以打印出对象的内存布局。
  • VisualVM / JProfiler / YourKit: 功能强大的性能分析工具,可以查看堆内存中对象的大小和数量。
分享:
扫描分享到社交APP
上一篇
下一篇