String 类在 Java 中是一个非常重要的类,它提供了多种构造函数来从不同的数据源创建字符串对象,理解这些构造函数有助于我们更高效、更安全地处理字符串。

核心要点
- 不可变性:最重要的一点是,
String对象在 Java 中是不可变的,一旦创建,其内容就不能被改变,任何看起来像修改字符串的操作(如substring(),concat(),replace())实际上都会返回一个新的String对象。 - 构造函数 vs. 字面量:创建字符串最常见的方式是使用字面量,
String str = "hello";,这种方式会尝试将字符串放入字符串常量池中,以提高性能和内存效率,而使用构造函数(如new String("hello"))则总是会在堆上创建一个新的对象,即使内容与池中已有的字符串相同。
常用的 String 构造函数
以下是 String 类中最常用的一些构造函数,并附有示例说明。
String()
- 描述:创建一个空的字符串对象。
- 参数:无
- 示例:
String emptyStr = new String(); System.out.println("空字符串的长度: " + emptyStr.length()); // 输出: 0 System.out.println("空字符串的内容: '" + emptyStr + "'"); // 输出: ''
String(String original)
-
描述:创建一个新字符串,它是参数字符串
original的副本,这是最常用的构造函数之一。 -
参数:
original- 一个String对象。 -
示例:
(图片来源网络,侵删)String original = "hello world"; String copy = new String(original); // 创建 original 的副本 System.out.println(copy); // 输出: hello world System.out.println(original == copy); // 输出: false,因为它们是两个不同的对象
String(char[] value)
-
描述:通过一个字符数组创建一个新的字符串对象。
-
参数:
value- 字符数组。 -
示例:
char[] chars = {'J', 'a', 'v', 'a'}; String fromCharArray = new String(chars); System.out.println(fromCharArray); // 输出: Java
String(char[] value, int offset, int count)
-
描述:通过字符数组的指定部分(从
offset开始,长度为count)创建一个新的字符串。
(图片来源网络,侵删) -
参数:
value: 字符数组。offset: 开始复制的索引位置。count: 要复制的字符数量。
-
示例:
char[] chars = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}; String subString = new String(chars, 6, 5); // 从索引6开始,取5个字符 System.out.println(subString); // 输出: World
String(byte[] bytes)
-
描述:使用平台的默认字符集(通常是 UTF-8)将指定的字节数组解码为字符串。
-
参数:
bytes- 字节数组。 -
示例:
byte[] utf8Bytes = "你好".getBytes(StandardCharsets.UTF_8); // 获取UTF-8编码的字节数组 String fromUtf8Bytes = new String(utf8Bytes); System.out.println(fromUtf8Bytes); // 输出: 你好
String(byte[] bytes, int offset, int length)
-
描述:使用平台的默认字符集,将字节数组的指定部分解码为字符串。
-
参数:
bytes: 字节数组。offset: 开始解码的索引位置。length: 要解码的字节数量。
-
示例:
byte[] allBytes = "Java Programming".getBytes(); String subBytesString = new String(allBytes, 5, 11); // 从索引5开始,取11个字节 System.out.println(subBytesString); // 输出: Programm
String(byte[] bytes, String charsetName)
-
描述:使用指定的字符集将整个字节数组解码为字符串,这在处理不同编码的文本时非常重要。
-
参数:
bytes: 字节数组。charsetName: 字符集的名称(如 "UTF-8", "ISO-8859-1")。
-
示例:
byte[] gbkBytes = "中文".getBytes("GBK"); // 使用GBK编码获取字节数组 // 如果用错误的字符集解码,会出现乱码 String wrongDecode = new String(gbkBytes, "UTF-8"); System.out.println("错误解码: " + wrongDecode); // 可能输出乱码 // 使用正确的字符集解码 String correctDecode = new String(gbkBytes, "GBK"); System.out.println("正确解码: " + correctDecode); // 输出: 中文
String(StringBuffer buffer)
-
描述:通过一个
StringBuffer对象创建字符串。 -
参数:
buffer-StringBuffer对象。 -
示例:
StringBuffer sb = new StringBuffer("Hello, "); String fromSb = new String(sb); fromSb += "World!"; System.out.println(fromSb); // 输出: Hello, World!
String(StringBuilder builder)
-
描述:通过一个
StringBuilder对象创建字符串。 -
参数:
builder-StringBuilder对象。 -
示例:
StringBuilder sb = new StringBuilder("Building a "); String fromSb = new String(sb); fromSb.append("String!"); System.out.println(fromSb); // 输出: Building a String!
构造函数 vs. 字面量:一个重要的区别
理解构造函数和字面量在创建对象时的区别至关重要。
public class StringExample {
public static void main(String[] args) {
// 使用字面量创建
String s1 = "hello";
String s2 = "hello";
// 使用构造函数创建
String s3 = new String("hello");
String s4 = new String("hello");
// == 比较的是对象的内存地址(引用)
// equals() 比较的是对象的内容
System.out.println("s1 == s2: " + (s1 == s2)); // true: 字面量会放入常量池,s1和s2指向同一个池中的对象
System.out.println("s1.equals(s2): " + s1.equals(s2)); // true: 内容相同
System.out.println("s3 == s4: " + (s3 == s4)); // false: new 总是创建新对象,s3和s4是两个不同的对象
System.out.println("s3.equals(s4): " + s3.equals(s4)); // true: 内容相同
System.out.println("s1 == s3: " + (s1 == s3)); // false: s1指向池中的对象,s3指向堆中的新对象
System.out.println("s1.equals(s3): " + s1.equals(s3)); // true: 内容相同
}
}
输出:
s1 == s2: true
s1.equals(s2): true
s3 == s4: false
s3.equals(s4): true
s1 == s3: false
s1.equals(s3): true
- 字面量 ():JVM 会在字符串常量池中查找是否存在相同内容的字符串,如果存在,则直接引用该对象;如果不存在,则创建一个新对象并存入池中,这有助于节省内存。
- 构造函数 (
new String(...)):总是在堆内存中创建一个新的String对象,无论内容是否已经存在于常量池中。
| 构造函数 | 描述 | 常见使用场景 |
|---|---|---|
String() |
创建空字符串 | 初始化一个空的字符串变量。 |
String(String original) |
复制一个现有字符串 | 需要一个字符串的副本,以确保原始字符串不被意外修改(虽然String本身不可变,但有时是为了逻辑上的隔离)。 |
String(char[] value) |
从字符数组创建 | 将字符数组内容转换为字符串。 |
String(char[] value, int offset, int count) |
从字符数组子集创建 | 只需要字符数组的一部分内容。 |
String(byte[] bytes) |
从字节数组(默认编码)创建 | 处理从文件或网络读取的字节流,并使用系统默认编码。 |
String(byte[] bytes, String charsetName) |
从字节数组(指定编码)创建 | 处理多语言文本,必须明确指定正确的字符集以避免乱码。 |
String(StringBuffer/Builder) |
从缓冲区创建 | 将 StringBuffer 或 StringBuilder 的内容转换为不可变的 String。 |
在实际开发中,推荐优先使用字面量来创建字符串,因为它更简洁且性能更好(得益于字符串常量池),只有在需要从其他数据类型(如字节数组、字符数组)显式构造字符串,或者需要强制创建一个新对象时,才应使用 new String() 构造函数。
