String 类在 Java 中是一个非常重要的不可变类,它提供了多种构造函数来从不同的数据源创建字符串对象。

Java String 的构造函数主要用于:
- 从字符数组 创建字符串。
- 从字节数组 创建字符串(需要指定字符编码)。
- 直接复制 另一个字符串的内容。
- 从部分字符/字节数组 创建字符串。
- 拼接其他对象 的字符串表示形式。
下面我们逐一详细介绍最常用和最重要的构造函数。
String() - 默认构造函数
这个构造函数创建一个空字符串对象。
String emptyStr = new String();
System.out.println("空字符串的长度: " + emptyStr.length()); // 输出: 0
System.out.println("空字符串的内容: '" + emptyStr + "'"); // 输出: ''
注意:虽然可以这样做,但在实际开发中,直接使用字符串字面量 来创建空字符串更为常见和高效,因为 Java 会对字符串字面量进行池化。

String anotherEmptyStr = ""; // 更推荐的方式
String(char[] value) - 从字符数组构造
这是最常用的构造函数之一,它将一个字符数组中的所有元素按顺序组合成一个新字符串。
char[] chars = {'J', 'a', 'v', 'a'};
String str = new String(chars);
System.out.println(str); // 输出: Java
String(char[] value, int offset, int count) - 从字符数组部分构造
这是上一个构造函数的扩展版本,它允许你从字符数组的指定 offset(偏移量)位置开始,取 count 个字符来创建新字符串。
value: 源字符数组。offset: 开始拷贝的索引位置(从0开始)。count: 要拷贝的字符数量。
char[] chars = {'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'};
// 从索引 6 开始,取 5 个字符
String str = new String(chars, 6, 5);
System.out.println(str); // 输出: World
边界检查:offset 或 count 超出数组范围,会抛出 IndexOutOfBoundsException 异常。
String(byte[] bytes) - 从字节数组构造
这个构造函数非常特殊,它使用平台的默认字符集(Charset)将字节数组解码成字符串。由于不同平台的默认字符集可能不同(如 Windows 可能是 GBK,Linux/macOS 通常是 UTF-8),这可能导致程序在不同环境下产生不一致的结果,因此应谨慎使用。

// 假设平台默认字符集是 UTF-8
byte[] utf8Bytes = {'H', 'e', 'l', 'l', 'o'}; // 这些字节在 UTF-8 中对应 'H', 'e', 'l', 'l', 'o'
String str1 = new String(utf8Bytes);
System.out.println(str1); // 输出: Hello
// 假设平台默认字符集是 GBK
byte[] gbkBytes = {-60, -29, -70, -61}; // 这两个字节在 GBK 编码中对应 '中'
String str2 = new String(gbkBytes);
System.out.println(str2); // 输出: 中 (在默认 GBK 平台上)
String(byte[] bytes, String charsetName) - 从字节数组构造(指定编码)
这是最安全、最推荐的从字节数组创建字符串的方式,它允许你明确指定字符编码(如 "UTF-8", "GBK", "ISO-8859-1"),确保程序在任何环境下都能得到一致的结果。
bytes: 源字节数组。charsetName: 字符编码的名称。
byte[] utf8Bytes = {-28, -72, -83, -27, -101, -67}; // "你好" 的 UTF-8 编码
// 正确使用 UTF-8 编码
String strCorrect = new String(utf8Bytes, "UTF-8");
System.out.println(strCorrect); // 输出: 你好
// 错误使用 GBK 编码
String strWrong = new String(utf8Bytes, "GBK");
System.out.println(strWrong); // 输出: ä½ å¥½ (乱码)
String(byte[] bytes, int offset, int length, String charsetName) - 从字节数组部分构造
这是上一个构造函数的扩展版本,可以从字节数组的指定位置和长度来创建字符串,并指定字符编码。
byte[] allBytes = {-28, -72, -83, -27, -101, -67, -28, -72, -83}; // "你好你好" 的 UTF-8 编码
// 从索引 3 开始,取 3 个字节
String str = new String(allBytes, 3, 3, "UTF-8");
System.out.println(str); // 输出: 你 (因为 "你" 的UTF-8编码正好是3个字节)
String(String original) - 复制构造函数
这个构造函数会创建一个新字符串,其内容与传入的 original 字符串完全相同。
重要概念:字符串不可变性与字符串池
- 不可变性:一旦
String对象被创建,它的内容就不能被修改。 - 字符串池:为了提高性能和节省内存,JVM 维护了一个特殊的内存区域,叫做“字符串常量池”,当你使用双引号 创建字符串时,JVM 会先检查池中是否已存在相同内容的字符串,如果存在,就直接返回池中的引用;如果不存在,就在池中创建一个新的并返回引用。
String s1 = "hello"; // "hello" 被放入字符串池
String s2 = new String("hello"); // "hello" 已经在池中,但 new 操作符会**在堆内存**中创建一个新的 String 对象
System.out.println(s1 == s2); // false
// s1 指向池中的 "hello"
// s2 指向堆中 newly created 的 "hello"
System.out.println(s1.equals(s2)); // true
// equals() 比较的是内容,内容相同,所以返回 true
new String("original") 的主要作用是强制在堆内存中创建一个新的字符串对象,即使池中已经存在相同内容的字符串。
String(StringBuffer buffer) 和 String(StringBuilder builder) - 从缓冲区构造
这两个构造函数分别从 StringBuffer 和 StringBuilder 对象创建字符串,它们会复制缓冲区中的内容来创建一个新的、不可变的 String 对象。
StringBuffer sb = new StringBuffer("Java");
String strFromSb = new String(sb);
System.out.println(strFromSb); // 输出: Java
StringBuilder sbl = new StringBuilder("Python");
String strFromSbl = new String(sbl);
System.out.println(strFromSbl); // 输出: Python
为什么需要它们?
StringBuffer 和 StringBuilder 是可变的,适用于频繁修改字符串的场景,当你完成了所有的拼接和修改操作,并最终需要一个不可变的字符串时,就可以使用这两个构造函数来生成最终的 String 对象。
String(StringBuilder builder) - 从 StringBuilder 构造
这是 JDK 9 中引入的,与 StringBuffer 的构造函数类似,用于从 StringBuilder 创建字符串。
// JDK 9+
StringBuilder sb = new StringBuilder("Hello");
String str = new String(sb);
System.out.println(str); // 输出: Hello
总结与最佳实践
| 构造函数 | 描述 | 示例 | 注意事项 |
|---|---|---|---|
String() |
创建一个空字符串 | new String() |
推荐使用 |
String(char[] value) |
从整个字符数组创建字符串 | new String(new char[]{'a','b'}) |
常用 |
String(char[] value, int offset, int count) |
从字符数组的指定部分创建字符串 | new String(chars, 1, 3) |
注意 offset 和 count 的边界 |
String(byte[] bytes) |
使用默认字符集从字节数组创建字符串 | new String(byteArray) |
不推荐,因平台依赖可能导致乱码 |
String(byte[] bytes, String charsetName) |
使用指定字符集从字节数组创建字符串 | new String(byteArray, "UTF-8") |
强烈推荐,保证跨平台一致性 |
String(String original) |
复制一个已存在的字符串,在堆上创建新对象 | new String("hello") |
区分 (地址) 和 equals() (内容) |
String(StringBuffer/StringBuilder) |
从可变的字符串缓冲区创建不可变的字符串 | new String(new StringBuffer("abc")) |
用于在完成字符串拼接后生成最终结果 |
核心建议:
- 优先使用字符串字面量:如
String s = "hello";,因为它利用了字符串池,效率更高。 - 处理字节数据时,务必指定编码:始终使用
new String(byte[], "charsetName")的形式,避免使用依赖平台默认编码的new String(byte[])。 - 理解
new String()的作用:它总是创建一个新的对象,即使内容相同,这可以用来绕过字符串池的引用。
