- 常量池的参与
String s1 = "hello";
:
- 当执行
String s1 = "hello";
时,JVM 首先会在字符串常量池中查找是否存在内容为 “hello” 的字符串对象。
- 如果存在,则直接将 s1 指向常量池中的这个字符串对象。
- 如果不存在,则在常量池中创建一个内容为 “hello” 的字符串对象,然后将 s1 指向它。
String s2 = new String("hello");
:
- 首先在字符串常量池中查找是否存在内容为 “hello” 的字符串对象。
- 如果不存在,会在常量池中创建一个内容为 “hello” 的字符串对象。
- 无论常量池中是否存在,
new String("hello")
都会在堆内存中创建一个新的字符串对象,然后将 s2 指向堆内存中的这个对象。
- 内存存储的不同
String s1 = "hello";
:s1 指向字符串常量池中的对象,只有一个对象(在常量池中)。
String s2 = new String("hello");
:s2 指向堆内存中的对象,同时常量池中也可能存在(若之前不存在则创建)一个相同内容的对象,即至少有一个堆对象,可能有一个常量池对象。
- 字符串常量复用的情况
- 当使用
String s = "xxx";
这种方式创建字符串时,如果常量池中已经存在相同内容的字符串对象,就会复用常量池中的对象。例如:
String s1 = "world";
String s2 = "world";
// 这里 s1 和 s2 指向常量池中的同一个 “world” 对象
- 对于
intern()
方法。如果一个字符串对象调用 intern()
方法,JVM 会在常量池中查找是否存在相同内容的字符串对象。如果存在,则返回常量池中对象的引用;如果不存在,则将该字符串对象添加到常量池中,并返回其引用。例如:
String s3 = new String("java");
String s4 = s3.intern();
// 假设常量池中之前没有 “java”,执行 intern() 后,s4 指向常量池中的 “java” 对象,
// 而 s3 仍然指向堆中的对象