Java中String构造方法性能差异显著:new String()和new String("")最轻量但无意义;new String(char[])等涉及数组复制;new String(byte[],Charset)编码开销最大;new String(String)零拷贝但新建对象引用,是防御性拷贝最优选。

Java 中 String 的多种构造方法在语义上看似等价,但底层实现和性能表现并不相同,尤其在内存分配、字符拷贝、字符串池交互等方面存在显著差异。关键在于:是否触发字符数组复制、是否共享底层数组、是否涉及编码转换或安全检查。
new String() 与 new String("") —— 最轻量,但无实际意义
两者都创建空字符串对象,不涉及字符拷贝,也不访问字符串常量池。区别仅在于字节码层面:new String() 调用无参构造器,new String("") 调用 String(String) 构造器(内部直接赋值引用)。后者多一次参数判空(但空字符串已确定非 null),实际性能差异可忽略。它们都生成堆上新对象,不复用常量池中的 ""。
new String(char[]) 和 new String(char[], int, int) —— 涉及数组复制,开销明显
这两个构造器会调用 Arrays.copyOfRange 创建底层数组的**完整副本**(即使范围是整个数组),确保字符串不可变性。这意味着:
- 每次调用都分配新 char[],产生额外 GC 压力
- 即使原 char[] 很大且只取其中几个字符,也会复制整个指定范围
- 无法复用原数组,也无法进入字符串池(除非后续调用
intern())
例如:new String(new char[]{'h','e','l','l','o'}, 1, 3) 会复制 {'e','l','l'} 成新数组,而非共享或截取视图。
立即学习“Java免费学习笔记(深入)”;
new String(byte[], Charset) —— 编码解码开销最大
该构造器需完成完整的字节解码流程:校验字节序列有效性、按 Charset 规则转换为 Unicode 码点、再构建 char[]。其成本取决于:
- 字节数组长度(线性扫描)
- Charset 实现复杂度(如 UTF-8 多字节解析 vs US-ASCII 单字节)
- 是否存在非法序列(触发异常或替换逻辑)
相比直接传 char[],它多了编码层抽象和错误处理路径,是所有重载中性能最低的之一。应避免在高频路径中使用,尤其当 byte[] 来源已知且编码固定时,优先考虑复用解码后的 String 或 char[]。
new String(String) —— 零拷贝,但新建对象引用
这是唯一一个不复制字符数据的构造器。它直接将入参的 value 字段(char[] 或 byte[])和 hash 字段赋值给新对象,仅增加一次堆对象分配。虽然内容共享,但由于 String 类本身不可变,这种共享是安全的。不过要注意:
- 它不触发 intern,新对象仍独立于字符串池
- 若原始 String 是通过 substring(旧版 JDK7u6 之前)等可能共享超长底层数组的方式创建,此构造器会延续该共享,造成内存泄漏风险(JDK7u6+ 已修复 substring 底层复制问题,此风险基本消失)
因此,new String(s) 是“防御性拷贝”需求中最高效的选择——你得到一个逻辑独立的对象,却不付出字符复制代价。
不复杂但容易忽略:多数场景下应直接使用字符串字面量或已有 String 引用,避免无谓的 new String(...);只有明确需要打破字符串池绑定或获得独立对象身份时,才选用构造器,且优先选 new String(String)。



















