String s1 = new String("abc"); s1.intern(); String s = "abc"; System.out.println(s==s1);返回的结果是什么
答案是 false。因为 s1.intern() 方法会将字符串 "abc" 添加到字符串常量池中,但是 s1 指向的是堆内存中的一个新的字符串对象,所以 s 和 s1 指向的不是同一个对象,所以返回 false。
String s1 = "abc"; String s2 = "abc"; System.out.println(s1 == s2); String s3 = "abc" + s1 + "def"; String s4 = "abcabcdef"; System.out.println(s3 == s4); String s5 = s3.intern(); System.out.println(s4 == s5);
s1和s2的结果是true,因为它们都指向字符串常量池中的同一个字符串对象"abc"。 s3和s4的结果是false,因为s是通过字符串拼接生成的新的字符串对象,在堆内存中分配。而s4是直接指向字符串常量池中的对象"abcabcdef"。 s5的结果是true,因为调用s3.intern()方法后,会在字符串常量池中查找是否存在"abcabcdef"这个字符串对象。由于之前已经创建过,所以s5会指向它。所以s4和s5都指向了同一个字符串对象。
String 声明一个字面量,和使用new 创建一个对象的区别是什么?
<<
在 Java 中声明字符串时,可以使用两种方式创建字符串实例:直接用字面量(String str = "abc";
)或通过 new
关键字显式地构造一个新的字符串对象 (String str = new String("abc");
)。这两种方式有显著的区别。
区别:
内存分配位置
- 使用 字面量定义(
"abc"
) 的时候, JVM 首先会在常量池中查找是否已经存在值为"abc"
的String
对象。如果不存在,则将该字符串放入常量池,并返回引用;否则直接返回已存在的常量池中的引用。 - 当使用
new
创建String
对象的时候,JVM 总是在堆(heap)上生成新的对象,即使它的内容已经在字符串常量池(String Pool)中存在了。
- 使用 字面量定义(
性能方面
- 直接使用字面量更高效,因为避免了重复创建相同的对象并且利用了缓存机制(即重用了常量池中的已有对象).
- 每次调用
new
,都会产生新对象,在大量数据处理的情况下可能会导致更多的垃圾回收(GC),从而影响效率。
比较结果不同
- 如果两个字符串都是通过字面量形式定义且具有相同的内容,那么它们实际上是同一个对象(reference equality),例如:
"hello".equals("hello") == true && ("hello" == "hello") == true
- 若采用
new
关键字分别初始化两份完全一样的字符串,虽然他们的.equals()
方法会判定他们相等,但其实际地址却是不一样的: 如下所示
- 如果两个字符串都是通过字面量形式定义且具有相同的内容,那么它们实际上是同一个对象(reference equality),例如:
public class Test {
public static void main(String[] args){
String s1 = "test";
String s2 = "test";
//true because both point to same object in pool.
System.out.println(s1==s2);
String s3 = new String("test");
String s4 = new String("test");
//false as they are different objects on heap.
System.out.println(s3==s4);
//True since content is equal.
System.out.println(s3.equals(s4));
}
}
上述例子说明即使是同样字符序列构成的新建字符串也不会共享同一存储空间。
解释
在第一种情况下 (不带
new
),当编译器遇到"test"
这样的文本串时,它实际上检查内部维护的一个全局表——所谓的“字符串池”。如果没有找到与之匹配的条目就添加进去并把指向那个地方的指针赋予变量名s1/s2
; 反之则复用现有的入口。因此在这种情形之下我们得到的是同一条记录的不同引用而已。第二个情况涉及到了显示构建动作(new operator卡顿触发执行自定义逻辑). 此过程无视任何预先准备好的资源而是单独开辟了一块区域存放这个特定实体的数据副本.
注意事项:
尽管如此,有时开发者还是希望强制让某个经由new出来的string加入到intern table里头去享受后续可能带来的好处,这时候就可以借助 intern() 方法手动完成此操作:
// After calling .intern(), 's5' will refer back to pooled version if already exists.
String s5 = new String("anotherTest").intern();
System.out.println(s5 == "anotherTest"); // This could be True now depending upon jvm implementation details.
以上就是关于Java中String
字面量和通过new
关键词创建的主要差异点以及背后的原因分析。
相关推荐












