在 Java 中,创建 String
对象有两种主要方式:
1. 使用双引号直接创建(推荐)
-
这是最常见的方式,直接使用双引号
" "
创建字符串。 -
这种方式的字符串会被放入 字符串常量池(String Pool),如果常量池中已经存在相同内容的字符串,则会复用该对象,而不会创建新的对象。
-
优点:节省内存,提高性能。
语法:
java
String str = "Hello";
示例:
java
String s1 = "Hello"; // 创建字符串并放入常量池 String s2 = "Hello"; // 复用常量池中的 "Hello" 对象 System.out.println(s1 == s2); // true,因为 s1 和 s2 指向同一个对象
2. 使用 new
关键字创建
-
通过
new
关键字创建字符串对象时,每次都会在堆内存中创建一个新的对象,即使内容相同。 -
这种方式创建的字符串不会放入字符串常量池,除非显式调用
intern()
方法。
语法:
java
String str = new String("Hello");
示例:
java
String s1 = new String("Hello"); // 在堆内存中创建一个新对象 String s2 = new String("Hello"); // 在堆内存中创建另一个新对象 System.out.println(s1 == s2); // false,因为 s1 和 s2 是不同的对象 System.out.println(s1.equals(s2)); // true,因为内容相同
3. 两种方式的区别
特性 | 双引号直接创建 | new 关键字创建 |
---|---|---|
对象存储位置 | 字符串常量池(String Pool) | 堆内存(Heap) |
是否复用对象 | 是(如果常量池中已存在相同内容) | 否(每次都会创建新对象) |
性能 | 更高(复用对象,节省内存) | 较低(每次创建新对象) |
适用场景 | 推荐使用,尤其是内容固定的字符串 | 需要显式创建新对象时使用 |
4. 字符串常量池(String Pool)
-
字符串常量池是 Java 中为了节省内存而设计的一种机制。
-
当使用双引号创建字符串时,Java 会先检查常量池中是否存在相同内容的字符串:
-
如果存在,则直接复用该对象。
-
如果不存在,则在常量池中创建一个新对象。
-
示例:
java
String s1 = "Hello"; // 创建并放入常量池 String s2 = "Hello"; // 复用常量池中的对象 String s3 = new String("Hello"); // 在堆内存中创建新对象 System.out.println(s1 == s2); // true System.out.println(s1 == s3); // false
5. intern()
方法
-
intern()
方法可以将new
创建的字符串对象放入字符串常量池(如果池中不存在相同内容)。 -
如果池中已存在相同内容,则返回池中的对象。
示例:
java
String s1 = new String("Hello"); // 在堆内存中创建新对象 String s2 = s1.intern(); // 将 s1 的内容放入常量池(如果不存在) String s3 = "Hello"; // 复用常量池中的对象 System.out.println(s1 == s2); // false System.out.println(s2 == s3); // true
6. 完整代码示例
java
public class Main { public static void main(String[] args) { // 方式 1:双引号直接创建 String s1 = "Hello"; String s2 = "Hello"; // 方式 2:new 关键字创建 String s3 = new String("Hello"); String s4 = new String("Hello"); // 比较引用 System.out.println("s1 == s2: " + (s1 == s2)); // true System.out.println("s1 == s3: " + (s1 == s3)); // false System.out.println("s3 == s4: " + (s3 == s4)); // false // 比较内容 System.out.println("s1.equals(s3): " + s1.equals(s3)); // true // 使用 intern() 方法 String s5 = s3.intern(); System.out.println("s1 == s5: " + (s1 == s5)); // true } }
7. 总结
-
双引号直接创建:推荐使用,性能高,适合内容固定的字符串。
-
new
关键字创建:适合需要显式创建新对象的场景。 -
字符串常量池:通过双引号创建的字符串会放入常量池,复用对象以节省内存。
-
intern()
方法:可以将new
创建的字符串放入常量池。
将字符串放入字符串常量池的意义:
将字符串放入字符串常量池(String Pool)是 Java 为了优化内存和提高性能而设计的一种机制。它的意义主要体现在以下几个方面:
1. 节省内存
-
字符串常量池是一个特殊的内存区域,用于存储字符串字面量(即用双引号直接创建的字符串)。
-
当多个字符串变量具有相同的内容时,它们可以共享常量池中的同一个对象,而不是在内存中创建多个重复的对象。
-
这样可以显著减少内存占用,尤其是在处理大量相同内容的字符串时。
示例:
java
String s1 = "Hello"; // 创建并放入常量池 String s2 = "Hello"; // 复用常量池中的对象 System.out.println(s1 == s2); // true,s1 和 s2 指向同一个对象
在这个例子中,s1
和 s2
共享常量池中的同一个 "Hello"
对象,而不是创建两个独立的对象。
2. 提高性能
-
由于字符串常量池中的对象可以被复用,减少了对象的创建和销毁次数,从而降低了垃圾回收(Garbage Collection)的压力。
-
字符串的比较操作(如
equals()
或==
)也会更快,因为如果两个字符串引用指向常量池中的同一个对象,可以直接判断它们相等,而不需要逐个字符比较。
示例:
java
String s1 = "Hello"; String s2 = "Hello"; // 使用 == 比较,直接判断引用是否相同 System.out.println(s1 == s2); // true
3. 避免重复创建
-
在 Java 中,字符串是不可变的(immutable),即一旦创建,内容就不能被修改。
-
如果每次都需要创建新的字符串对象,会导致大量重复的对象占用内存。
-
通过字符串常量池,可以避免重复创建相同内容的字符串对象。
示例:
java
for (int i = 0; i < 1000; i++) { String s = "Hello"; // 复用常量池中的对象,而不是创建 1000 个新对象 }
4. intern()
方法的作用
-
对于通过
new
关键字创建的字符串,它们不会自动放入常量池。 -
如果希望将这些字符串放入常量池以复用,可以调用
intern()
方法。 -
intern()
方法会检查常量池中是否存在相同内容的字符串:-
如果存在,则返回常量池中的对象。
-
如果不存在,则将当前字符串放入常量池并返回。
-
示例:
java
String s1 = new String("Hello"); // 在堆内存中创建新对象 String s2 = s1.intern(); // 将 s1 的内容放入常量池(如果不存在) String s3 = "Hello"; // 复用常量池中的对象 System.out.println(s1 == s2); // false System.out.println(s2 == s3); // true
5. 适用场景
-
适合放入常量池的字符串:
-
内容固定的字符串(如常量、配置项、枚举值等)。
-
频繁使用的字符串(如日志消息、错误提示等)。
-
-
不适合放入常量池的字符串:
-
动态生成的字符串(如用户输入、随机字符串等)。
-
生命周期较短的字符串(如临时变量)。
-
6. 总结
将字符串放入常量池的主要意义在于:
-
节省内存:通过复用对象,减少重复字符串的内存占用。
-
提高性能:减少对象创建和垃圾回收的开销,加快字符串比较速度。
-
避免重复创建:对于内容相同的字符串,复用常量池中的对象。