跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Java 中 String 对象创建机制解析

Java String 对象创建涉及字符串驻留池、堆内存分配及常量折叠机制。使用双引号赋值时,若常量池存在则复用,否则新建;使用 new 关键字则在堆中强制创建新对象。字符串拼接在编译期若均为字面量会进行常量折叠,合并为一个对象;若包含变量或 new 对象,则通过 StringBuilder 运行时拼接,生成额外对象。掌握这些机制有助于优化内存使用,避免不必要的对象创建。

赛博行者发布于 2025/2/3更新于 2026/5/2817 浏览
Java 中 String 对象创建机制解析

在开始之前,我们先了解一下字符串驻留的概念。

当同时创建多个相同的字符串字面量时,只有一个字符串常量被存储在运行时常量池中。

例如:

String a = "abc";
String b = "abc";
// String c = new String("abc");

此时虽然创建了两次 String 引用,但在运行时常量池中只有一个 "abc"。对于 String c = new String("abc"),可以通过 c.intern() 获取该字符串在运行时常量池中的引用对象,因此:

String a = new String("abc");
String b = new String("abc");
System.out.println(a == b); // false
System.out.println(a.intern() == b.intern()); // true

1. String a="abc"与 String b=new String("abc")一样吗?

首先是不一样的,也不是语法糖。我们看以下代码:

public static void main(String[] args) {
    String a = "abc";
    String b = "abc";
    String c = new String("Hello world");
    String d = new String("abc");
    int length = "abc".length();
}

从字节码分析可以看到,String a = "abc" 只创建了一个对象(即 "abc",位于运行时常量池)。而 String a = new String("abc") 会创建额外的对象。使用 new 关键字意味着在堆内存中也创建了一个对象。

a、b 两个对象都是通过 ldc 指令将常量 "abc" 加载进操作数栈的,所以 a == b 为 true。然而 String d = new String("abc") 会在堆中新建一个 String 对象,所以 d == b 为 false。

通常创建 String 对象时,推荐使用双引号方式,因为 new 的方式会额外创建一个对象。

2. String a="abc"要创建几个对象?

通过上面的解释可知,String a = "abc" 会创建一个对象(在运行时常量池),而 String a = new String("abc") 会创建两个对象(一个在运行时常量池的 "abc",一个在堆里面)。需要注意的是,这是在两者不同时出现的情况下。

3. String a="abc"; String b=new String("abc") 又要创建几个对象?

理解上述内容后便容易解答。当 String a = "abc" 与 String b = new String("abc") 同时出现时,总共会创建 2 个对象。

首先 String a = "abc" 在运行时常量池中创建了一个对象。当执行 String b = new String("abc") 时,由于运行时常量池中已存在对象 "abc",则不需要在常量池中新建,只需在堆中创建一个对象即可。

4. String a="abc"; String b="abc"; 那么 a==b 吗?

结果为 true。正如前文所述,a 与 b 都指向了运行时常量池中的 "abc"。

5. String a="hello"+"world", 创建几个对象?String b="helloworld", a==b 吗?

这里涉及常量折叠概念。这是在早期编译阶段的一种优化。例如:

int a = 1 + 2;

经过常量折叠后,1、+、2 变成了字面量 3,所以在代码中定义 int a = 1 + 2 并不比 int a = 3 增加程序运行期的运算量。

相应的,"hello"、"world" 也是常量,经过常量折叠后与 String b = "helloworld" 无异。所以 a == b 为 true。因此 String a = "hello" + "world" 也只会产生一个对象。

查看字节码验证:

public class Main {
    public static void main(String[] args) {
        String a = "helloWorld";
        String b = "hello" + "World";
        System.out.println(a == b);
    }
}

使用 javap -verbose Main 查看,只有合并后的常量,而没有单独的 hello 和 world。且 ldc 加载的常量索引相同,说明 String a = "helloworld" 与 String b = "hello" + "world" 没有区别。

String c=new String("hello"+"world") 创建了几个对象?

由于经过常量折叠,"hello" + "world" 与 "helloworld" 没有区别,所以:

String c = new String("hello" + "world");

与

String c = new String("helloworld");

效果一致,String c = new String("hello" + "world") 也只产生两个对象(一个常量池,一个堆)。

6. 下面程序创建几个对象?特别注意 String b=new String("hello")+new String("world") 产生几个对象?

String a = "hello" + "world";
String b = new String("hello") + new String("world");

对于 String a = "hello" + "world",肯定只创建一个对象。

而对于 String b = new String("hello") + new String("world"),会产生 7 个对象:

  1. "hello" 与 "world" 两个在运行时常量池的对象。
  2. new String("hello") 与 new String("world") 两个在堆中的对象。
  3. Java 8 中字符串拼接使用 StringBuilder 实现,需要创建一个 StringBuilder 对象。
  4. StringBuilder 内部有一个 char[] 数组,数组本身也是一个对象。
  5. 调用 StringBuilder 对象的 toString() 方法时,又会 new 一个 String 对象。

综上,共产生 7 个对象。

查看 StringBuilder.append(String) 源码:

@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

它调用了父类方法 super.append(str):

public AbstractStringBuilder append(String str) {
    if (str == null) return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count); // 这里的 value 是一个 char[] 数组
    count += len;
    return this;
}

看到 value 了吗?它是一个 char[] 数组,数组也算对象:

/**
 * The value is used for character storage.
 */
char[] value;

至此第 6 个对象找到了。再看第 7 个对象,随后调用 toString() 方法:

@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count); // 这里产生了一个对象
}

至此第 7 个对象就出现了。

目录

  1. 1. String a="abc"与 String b=new String("abc")一样吗?
  2. 2. String a="abc"要创建几个对象?
  3. 3. String a="abc"; String b=new String("abc") 又要创建几个对象?
  4. 4. String a="abc"; String b="abc"; 那么 a==b 吗?
  5. 5. String a="hello"+"world", 创建几个对象?String b="helloworld", a==b 吗?
  6. String c=new String("hello"+"world") 创建了几个对象?
  7. 6. 下面程序创建几个对象?特别注意 String b=new String("hello")+new String("world") 产生几个对象?
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 二分查找实战:山峰数组的峰顶索引与寻找峰值
  • 数据结构:常见排序算法原理与实现
  • Java 注解与反射实战:自定义日志与参数校验注解实现
  • 10 款 AI 论文写作工具实测与使用指南
  • Spring Bean 管理与 Spring Boot 自动配置原理
  • 学术论文如何应对查重与 AIGC 检测的双重挑战
  • AI 产品经理核心能力与实施框架指南
  • Vector 与 pthread_create 线程函数的使用注意事项
  • Rust 核心基础数据类型与变量系统
  • 微信小程序全局配置 window 属性详解及常见误区
  • Kali Linux 虚拟机安装教程
  • 无人机目标检测中的自适应图像变焦与边界框变换
  • 二分查找实战:山峰数组的峰顶索引与寻找峰值
  • AI 时代重读《人人都是产品经理》:核心内核与落地实践
  • Java Math 类核心方法与实战应用
  • 前端请求后端接口 404/405/500 状态码排查与解决指南
  • 基于 C++11 手写前端 Promise 实现
  • FPGA 是什么?核心原理与行业应用详解
  • Qwen2.5-32B-Instruct 本地部署指南:快速搭建 AI 写作助手
  • 美赛备赛指南:排版工具选择、论文阅读与避坑策略

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online