杰瑞科技汇

Java String构造函数有哪些?

String 类在 Java 中非常特殊,它被 final 修饰,意味着它不能被继承,Java 为了提高字符串的性能和内存使用,引入了字符串常量池的概念,这使得 String 的构造方式与其他普通对象有所不同。

Java String构造函数有哪些?-图1
(图片来源网络,侵删)

String 类提供了非常多的构造函数,以满足不同场景下创建字符串对象的需求,下面我将它们分类进行详细解释。


从字符数组构造

这是最常见的一类构造函数,允许你将一个字符数组转换成字符串。

String(char[] value)

这是最基础的构造函数,它将整个字符数组的内容复制到一个新的 String 对象中。

char[] chars = {'H', 'e', 'l', 'l', 'o'};
String str1 = new String(chars);
System.out.println(str1); // 输出: Hello

String(char[] value, int offset, int count)

这个构造函数允许你从字符数组的指定 offset(偏移量)位置开始,取 count 个字符来构造字符串。

Java String构造函数有哪些?-图2
(图片来源网络,侵删)
char[] chars = {'W', 'o', 'r', 'l', 'd', '!', 'J', 'a', 'v', 'a'};
String str2 = new String(chars, 6, 4); // 从索引6开始,取4个字符
System.out.println(str2); // 输出: Java

从字节数组构造

这类构造函数在处理 I/O 流、网络传输或文件读写时非常有用,因为数据通常以字节数组的形式存在,这里涉及到字符编码的问题,非常重要。

String(byte[] bytes)

使用平台默认的字符集(charset,通常是 UTF-8 或系统默认编码)将字节数组解码成字符串。

byte[] bytes = {72, 101, 108, 108, 111}; // "Hello" 的 UTF-8 编码
String str3 = new String(bytes);
System.out.println(str3); // 输出: Hello

String(byte[] bytes, int offset, int length)

与上面类似,但只处理字节数组中从 offset 开始的 length 个字节。

byte[] bytes = {87, 111, 114, 108, 100, 33};
String str4 = new String(bytes, 0, 5); // 取前5个字节
System.out.println(str4); // 输出: World

String(byte[] bytes, String charsetName)

使用指定的字符集(如 "UTF-8", "GBK", "ISO-8859-1")将整个字节数组解码成字符串。这是处理编码问题最推荐的方式

Java String构造函数有哪些?-图3
(图片来源网络,侵删)
byte[] gbkBytes = {-60, -29, -70, -61}; // "你好" 在 GBK 编码下的字节数组
// 错误示范:用错误的编码解码
String wrongStr = new String(gbkBytes, "UTF-8"); // 可能会乱码,输出类似: 您好
System.out.println("错误解码: " + wrongStr);
// 正确示范:用正确的编码解码
String correctStr = new String(gbkBytes, "GBK"); // 输出: 你好
System.out.println("正确解码: " + correctStr);

String(byte[] bytes, int offset, int length, String charsetName)

结合了以上两个功能,指定范围并使用指定字符集。


从字符串或其部分构造

String(String original)

这个构造函数看起来有点奇怪,因为它接收一个 String 对象作为参数,然后创建一个新的 String 对象,新对象的值与原始对象相同。

重要知识点:字符串不可变性与 intern() 方法

  1. 不可变性String 对象一旦创建,其内容就不能被修改,这个构造函数会创建一个新的 String 实例,即使它的内容与另一个实例完全相同。

  2. 字符串常量池:为了优化内存,JVM 维护了一个字符串常量池,当你使用字面量(如 String s = "hello";)创建字符串时,JVM 会先检查池中是否存在该字符串,如果存在则直接引用,不存在则创建并存入池中。

  3. new String() vs. 字面量

    • String s1 = "hello"; // s1 直接指向字符串常量池中的 "hello"
    • String s2 = new String("hello"); // JVM 会在堆上创建一个新的 String 对象,其内容是 "hello"。"hello" 这个字面量会被放入常量池(如果还没有的话),s2 指向堆中的新对象。

    s1 == s2 的结果是 false,因为它们是两个不同的对象(一个在池中,一个在堆中)。 s1.equals(s2) 的结果是 true,因为它们的内容相同。

String original = "hello";
String str5 = new String(original); // 在堆上创建了一个新的 "hello" 对象
System.out.println(original == str5);        // false
System.out.println(original.equals(str5));   // true

String(StringBuffer buffer)

使用 StringBuffer 对象的内容创建一个不可变的 String 对象。

StringBuffer sb = new StringBuffer("Java");
String str6 = new String(sb);
System.out.println(str6); // 输出: Java

String(StringBuilder builder)

StringBuffer 类似,但使用 StringBuilder,这是 Java 5 引入的、非线程安全的版本,性能更高。

StringBuilder sb = new StringBuilder("StringBuilder");
String str7 = new String(sb);
System.out.println(str7); // 输出: StringBuilder

其他构造函数

String(int[] codePoints, int offset, int count)

这是一个比较特殊的构造函数,它基于 Unicode 代码点数组来创建字符串,代码点可以表示一个字符,也可以表示一个代理对(用于表示某些特殊的 Unicode 字符,如某些表情符号)。

// 'A' 的代码点是 65, 'B' 是 66, '€' (欧元符号) 的代码点是 8364
int[] codePoints = {65, 66, 8364};
String str8 = new String(codePoints, 0, 3);
System.out.println(str8); // 输出: AB€

重要知识点总结

构造函数示例 描述 关键点
new String(char[] value) 从整个字符数组创建。 复制字符数组内容到新 String 对象。
new String(byte[] bytes) 使用默认字符集从字节数组创建。 依赖平台默认编码,可能产生乱码。
new String(byte[] bytes, "UTF-8") 使用指定字符集从字节数组创建。 推荐使用,明确编码,避免乱码。
new String(String original) 从另一个 String 对象创建。 创建一个相同的不可变对象。
String s = "literal"; 使用字符串字面量创建。 会检查字符串常量池,优化内存。
new String() vs. "literal" new String() 创建一个空字符串对象; 也是空字符串,但可能指向池中的同一个实例。 注意空字符串字面量 的池化行为。

最佳实践

  1. 优先使用字面量:对于常规字符串,直接使用 String s = "hello";,这是最简洁、最高效的方式,并且能充分利用字符串常量池的优化。
  2. 处理 I/O 时指定编码:当从文件、网络或数据库等来源获取字节数据并转换为字符串时,务必使用 String(byte[] bytes, String charsetName) 构造函数并明确指定正确的字符集(如 "UTF-8"),以避免乱码问题。
  3. 理解 new String() 的开销:除非你有特殊需求(你需要一个独立于常量池的 String 实例,或者你想确保字符串不被外部修改),否则尽量避免使用 new String("literal") 这种方式,因为它会多创建一个不必要的对象。
  4. 区分 和 equals():永远记住, 比较的是对象的内存地址(引用),而 String.equals() 比较的是字符串的内容,对于字符串,内容比较才是最常见的。
分享:
扫描分享到社交APP
上一篇
下一篇