基本操作
1.String s = “a”;
堆中:创建String(“a”)对象
常量池(StringTable): "a"字面量引用 -> 堆中String(“a”)对象
2.String s = “a” + “a”;
堆中:String(“aa”)对象
常量池: "aa"字面量 -> 堆中String(“aa”)对象
注意:“a” + "a"编译时被合为"aa"字面量,也就是没有存在"a"字面量,所以"a"没有加入常量池
3.String s = new String(“a”);
堆中:
1.s引用 -> String(“a”)对象
2."a"字面量 -> String(“a”)对象
常量池: "a"字面量 ->堆中("a"字面量 -> String(“a”)对象)
4.String s = new String(“a”) + “a”;
堆中:
1.s引用 -> String(“aa”)对象
2."a"字面量 -> String(“a”)对象
常量池: "a"字面量 ->堆中("a"字面量 -> String(“a”)对象)
注意:s引用指向的String(“aa”)对象,因为是new出来的,也就是没有存在"aa"字面量,所以没有加入常量池
复合判断
1.
String s = "a";
s.intern();
堆中:s引用 -> String(“a”)对象
常量池: "a"字面量 -> (s引用 -> 堆中String(“a”)对象)
注意: 常量池中已有"a"字面量,s.intern()不会在常量池再放"a"字面量了
2.
String s = new String("a");
s.intern();
堆中:
1.s引用 -> String(“a”)对象
2."a"字面量 -> String(“a”)对象
常量池: "a"字面量 -> 堆中("a"字面量 -> String(“a”)对象)
注意: 常量池中已有"a"字面量,s.intern()不会在常量池再放"a"字面量了
3.
String s = new String("a") + "a";
s.intern();
堆中:
1.s引用 -> String(“aa”)对象
2."a"字面量 -> String(“a”)对象
常量池:
1."aa"字面量 -> (s引用 -> String(“aa”)对象)
2."a"字面量 -> 堆中("a"字面量 -> String(“a”)对象)
注意:第一句new String时常量池没有"aa"字面量,第二句s.intern()将"aa"字面量添加进常量池
4.
String s = new String("a") + "a";
String s1 = "aa";
System.out.println(s == s1); //false
堆中:
1.s引用 -> String(“aa”)对象
2."a"字面量 -> String(“a”)对象
3.s1引用 -> String(“aa”)对象
常量池:
1."aa"字面量 -> (s1引用 -> String(“aa”)对象)
2."a"字面量 -> 堆中("a"字面量 -> String(“a”)对象)
注意: 第一句new String并没有将"aa"添加到常量池,第二句中出现了字面量"aa",此时s1指向堆中新创建的一个String(“aa”),并且该字面量会添加到常量池
5.
String s = new String("a") + "a";
s.intern();
String s1 = "aa";
System.out.println(s == s1); //true
堆中:
1.s引用 -> String(“aa”)对象
2."a"字面量 -> String(“a”)对象
常量池:
1."aa"字面量 -> (s引用 ->堆中String(“aa”)对象)
2."a"字面量 -> 堆中("a"字面量 -> String(“a”)对象)
注意:第二句s.intern()会将s引用的String(“aa”)添加到常量池中,所以第三句"aa"字面量看到常量池中已有"aa",就将s引用的String(“aa”)赋值给s1
6.
String s = new String("a") + "a";
String s1 = "aa";
System.out.println(s == s1); //false
System.out.println(s.intern() == s); //false
System.out.println(s.intern() == s1); //true
堆中:
1.s引用 -> String(“aa”)对象
2."a"字面量 -> String(“a”)对象
3.s1引用 -> String(“aa”)对象
常量池:
1."aa"字面量 -> (s1引用 -> String(“aa”)对象)
2."a"字面量 -> 堆中("a"字面量 -> String(“a”)对象)
注意:第二句"aa"字面量会在创建String(“aa”)对象,赋值给s1,并且会将"aa"字面量加到常量池中。s.intern()会检测常量池中是否有"aa",如果没有就放入s引用,有的话直接返回常量池中"aa"引用的对象,而常量池中的“aa”放的是s1,所以s.intern() = s1
总结
关于字符串的几种情况总结下:
| 堆 | 字符串常量池 | |
|---|---|---|
| 字面量(用""包起来的串值) | 常量池没有的话就new | 常量池中有该字面量,就不用放入了。 没有的话就在堆中new一个,并在常量池里引用到堆中new的String对象 |
| new String(“a”) | new一个String对象 | new String(“a”)创建的String对象不会放入常量池,但是"a"是字面量。 只要出现字面量要按上面字面量来处理 |
| “a” + “a” | 常量池没有的话会new String(“aa”) | “a” + “a"编译时会合并为"aa”,按"aa"字面量处理 |
| new String(“a”) + “a” | new + 字面量,底层是用StringBuilder的append方法,最后会new String(“aa”) 过程当中没有出现"aa"字面量。 常量池没有"a"的话会new String(“a”) | 只会处理"a"字面量 |
| new String(“a”) + new String(“a”) | 同上,底层是用StringBuilder的append方法,最后会new String(“aa”) 。 常量池没有"a"的话会new String(“a”) | 只会处理"a"字面量 |
| s.intern() | 不处理 | 常量池中没有s的字面量,就把s字面量加到常量池,且常量池中字面量指向s。 如果常量池已经有s的字面量,则返回常量池中字面量指向的堆中的String对象 |