String str = “i” 与 String str = new String(“i”) 一样吗?
参考回答**
不完全一样。
String str = "i";
和 String str = new String("i");
的主要区别在于对象的创建方式和存储位置:
String str = "i";
- 这是直接使用字符串字面量的方式,字符串
"i"
会存储在字符串常量池中。 - 如果常量池中已经有
"i"
,则直接引用该对象;否则会在常量池中创建"i"
。
- 这是直接使用字符串字面量的方式,字符串
String str = new String("i");
- 这是通过
new
关键字显式创建的字符串对象。 - 它会在堆内存中创建一个新的字符串对象,内容为
"i"
,即使常量池中已经有"i"
,堆中也会创建新的对象。
- 这是通过
因此:
String str = "i";
可能复用常量池中的对象。String str = new String("i");
一定会创建一个新的对象。
详细讲解与拓展
1. 字符串常量池
字符串常量池是 Java 中专门用于存储字符串字面量的内存区域。其特点是:
- 常量池中的字符串是唯一的,不会有重复的内容。
- 如果两个字符串字面量相同,则它们会指向常量池中的同一个对象。
例如:
String str1 = "i";
String str2 = "i";
System.out.println(str1 == str2); // true
这里,str1
和 str2
指向的是常量池中的同一个对象。
2. new String("i")
的行为
当使用 new String("i")
时:
- 首先检查字符串常量池中是否有 “i”:
- 如果有,则直接引用常量池中的
"i"
。 - 如果没有,则在常量池中创建
"i"
。
- 如果有,则直接引用常量池中的
- 然后,
new String("i")
会在堆内存中创建一个新的String
对象,并将常量池中的"i"
复制到堆中的新对象。
例如:
String str1 = "i"; // 引用常量池中的 "i"
String str2 = new String("i"); // 创建堆内存中的新对象
System.out.println(str1 == str2); // false
str1
指向的是常量池中的 "i"
,而 str2
指向的是堆中的新对象,因此两者地址不同,==
比较返回 false
。
3. equals()
方法的结果
虽然 str1
和 str2
的内存地址不同,但它们的内容是相同的:
System.out.println(str1.equals(str2)); // true
equals()
方法比较的是字符串的内容,而不是引用地址。
4. 具体例子
public class Main {
public static void main(String[] args) {
String str1 = "i";
String str2 = new String("i");
String str3 = "i";
System.out.println(str1 == str2); // false
System.out.println(str1 == str3); // true
System.out.println(str1.equals(str2)); // true
}
}
解释:
str1
和str3
都指向常量池中的"i"
,所以str1 == str3
返回true
。str2
是通过new
创建的对象,存储在堆中,因此str1 != str2
。str1.equals(str2)
返回true
,因为它们的内容相同。
5. intern()
方法的作用
如果希望通过 new String()
创建的字符串对象也使用常量池,可以调用 intern()
方法:
String str1 = "i";
String str2 = new String("i").intern();
System.out.println(str1 == str2); // true
解释:
-
intern()
方法会检查常量池中是否存在相同内容的字符串:
- 如果存在,则返回常量池中的字符串引用;
- 如果不存在,则将字符串加入常量池并返回其引用。
6. 两种方式的对比总结
特性 | String str = "i"; |
String str = new String("i"); |
---|---|---|
对象创建位置 | 字符串常量池 | 堆内存 |
是否创建新对象 | 如果常量池中已有,不创建 | 一定会创建新对象 |
是否占用额外内存 | 否(复用常量池中的对象) | 是 |
适用场景 | 需要复用字符串(大多数场景) | 显式创建不同的字符串对象 |
7. 总结
- 直接赋值(
String str = "i";
):- 推荐使用这种方式,既简洁又高效。
- 优点是会复用字符串常量池中的对象,避免重复创建。
- 显式创建(
String str = new String("i");
):- 会创建额外的对象,占用更多内存。
- 通常不推荐使用,除非有特殊需求(如明确需要不同的对象引用)。
两种方式的核心区别在于对象存储位置和是否会复用常量池中的对象。