【Java SE】字符串常量池
·
JVM字符串常量池:位置、创建流程、对象个数与 intern
在 Java 里,String 无处不在:JSON、SQL、日志、配置……字符串创建频繁,如果每次都分配新对象,会带来明显的内存与 GC 压力。于是 JVM/类加载体系为 字符串字面量提供了一个复用池:字符串常量池(String Intern Pool)。
字符串在堆内存中的存储结构 ⭐
字面量:直接走常量池复用
String a = "abc";
String b = "abc";
System.out.println(a == b); // true(同一份池对象)

- 当执行
String a= "abc"时,JVM 会先去 StringTable 查找是否已有 “abc”。如果没有,则在堆中创建对象,并将其引用存入 StringTable;如果有,则直接返回已存在的引用。
String a = "abc"
String b = "ab";
System.out.println(a == b); // true(同一份池对象)

new String(“abc”):堆上再来一份
String a = "abc";
String b = new String("abc");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true

- 执行
String b = new String("abc");时,JVM 会直接在堆中创建新的 String 对象,不会自动去 StringTable 里查找或存储。
常见写法到底创建几个字符串对象?
同样字面量多次出现
String s1 = "abc";
String s2 = "abc";
String s3 = "abc";

new String(“abc”) 出现多次
String s4 = new String("abc");
String s5 = new String("abc");

常量拼接(编译拼接)
new String(“a” + “b”)和 “a” + “b”
String s6 = new String("a" + "b");
String s7 = "a" + "b";
-
String s6 = new String("a" + "b");等价于String s6 = "ab"; -
String s7 = "a" + "b";等价于String s7 = "ab"; -
可以通过
javap -verbose反编译这段代码来验证:// 源代码 String s7 = "a" + "b"; String s8 = "ab";反编译字节码展示(关键部分):
0: ldc #2 // String ab 2: astore_1 3: ldc #2 // String ab 5: astore_2可以看到,
s7和s8的字节码指令完全一样,都是ldc #2(将常量池中编号为 #2 的常量 “ab” 推入栈顶)。这证明编译器已经把"a" + "b"直接优化成了"ab"。
final 常量拼接:“a” + “b”
final String s9 = "a";
String s10 = s9 + "b";
- 等价于
String s10 = "ab";
变量拼接(运行拼接)
s1+s2
String s11= "a";
String s12 ="b";
String s13 = s11 + s12;
等价于
String s11 = "a";
String s12 = "b";
String s13 = new StringBuilder()
.append(s11)
.append(s12)
.toString();
new String(“a”) + “b”;
String s14 = new String("a") + "b";
等价于
String s14 = new StringBuilder()
.append(new String("a"))
.append("b")
.toString();
new String(“a”) + new String(“b”)
String s15= new String("a") + new String("b")
等价于
String s15 = new StringBuilder()
.append(new String("a"))
.append(new String("b"))
.toString();
intern():让等值字符串指向池里的那一个
String x = new String("123"); // 堆对象
String y = x.intern(); // 返回池中对应对象的引用
System.out.println(y == "123"); // true
理解一句话就够了:intern() 返回常量池中等内容字符串的引用;如果池里没有,可能把当前字符串(或其等价表示)放进去,再返回池引用。
更多推荐


所有评论(0)