String的创建过程
1. 直接使用双引号声明出来的String
1.1 创建逻辑说明
String str = "xyz";
创建说明:
在常量池中查看是否有xyz对象,如果不存在先在常量池创建xyz对象,创建后返回常量池中的xyz对象的引用给str;如果常量池中存在xyz对象则直接返回常量池中xyz对象的引用给str。
// 创建过程大致逻辑
if (常量池中存在内容为xyz对象/引用) {
返回常量池中xyz对象/引用的引用给str
}
else if (常量池中不存在xyz对象/引用) {
在常量池创建xyz对象;
返回在常量池中创建的xyz对象的引用给str
}
该创建方式一共创建一个对象,为常量池中的xyz ,不在堆中创建任何对象
1.2 举例
String str1 = "xyz";
String str2 = "xyz";
System.out.println(str1 == str2); // true
创建过程:
- 创建str1,在常量池中查看是否有xyz对象,发现没有,就在常量池中创建xyz对象,返回在常量池创建的xyz对象的引用。
- 创建str2,在常量池中查看是否有xyz对象,发现存在(是创建str1时创建的xyz对象),直接返回常量池中的xyz对象的引用。
- str1和str2都为str1创建时在常量池生成的xyz对象,为true
// jdk8
String str1 = new String("x") + new String("yz");
str1.intern();
String str2 = "xyz";
System.out.println(str2 == str1); // true
创建过程:
- new String(“x”):常量池x, 堆new String(“x”)
- new String(“yz”):常量池x, 堆new String(“yz”)
- new String(“x”) + new String(“yz”):堆StringBuild, new String(“xyz”)
- str1.intern();:常量池没有内容为str1内容的对象/引用,将new String(“xyz”)的引用即str1写入常量池
- String str2 = “xyz”;:在常量池中查找内容为xyz的对象/引用,str1.intern()时写入的str1符合条件,返回str1的引用
- str2为str1的引用,str1又为new String(“xyz”)的引用,str2和str1都为new String(“xyz”),true.
2. new方法创建String
2.1 创建逻辑说明
String str = new String("xyz");
创建说明:
查看常量池中是否存在xyz对象,如果常量池中不存在xyz对象,在常量池中创建xyz对象,然后再在堆中创建new String(“xyz”)对象,返回new String(“xyz”)的引用给str;如果常量池中存在xyz对象,不在常量池中创建xyz对象,直接在堆中创建new String(“xyz”)对象,返回new String(“xyz”)的引用给str。
// 创建过程大致逻辑
if (常量池中存在xyz对象/引用) {
在堆中创建new String("xyz")对象;
返回在堆中创建new String("xyz")对象的引用给str;
}
else if (常量池中不存在xyz对象/引用) {
在常量池中创建xyz对象;
在堆中创建new String("xyz")对象;
返回在堆中创建new String("xyz")对象的引用给str;
}
-
该创建方式常量池存在创建一个对象(堆中创建的new String(“xyz”)对象)
-
该创建方式常量池不存在创建两个对象(常量池xyz对象,堆中创建的new String(“xyz”)对象)
2.2 举例
String str1 = new String("xyz");
String str2 = new String("xyz");
System.out.println(str1 == str2); // false
创建过程:
- 创建str1,在常量池中查看是否存在xyz对象,发现没有,在常量池中创建xyz对象,再在堆中创建new String(“xyz”)(下面用new String(“xyz”)-str1说明),将new String(“xyz”)的引用返回给str1。(创建了2个对象)
- 创建str2,在常量池中查看是否存在xyz对象,发现存在(是创建str1时创建的xyz对象)直接在堆中创建new String(“xyz”)(下面用new String(“xyz”)-str2说明),将new String(“xyz”)的引用返回给str2。 (创建了1个对象)
- str1为堆中new String(“xyz”)-str1对象的引用,str2为为堆中new String(“xyz”)-str2对象的引用,false。
创建完后对象分别为:
- 常量池(1个对象):xyz
- 堆(2个对象):new String(“xyz”)-str1, new String(“xyz”)-str2
其他说明:
str1为堆中new String(“xyz”)-str1对象的引用
str2为为堆中new String(“xyz”)-str2对象的引用
3. 两个引号相加
String str1 = "x" + "yz";
String str2 = "xyz";
System.out.println(str1 == str2); // true
创建过程:
- str1在编译过程会进行优化,优化为str1 = “xyz”;所以该情况等价与1.2举例相同
创建完后对象分别为:
- 常量池(1个对象):xyz
- 堆(0个对象)
其他说明:
str1, str2为常量池中xyz对象的引用
4. 两个new相加
String str = new String("x") + new String("yz");
创建过程:
-
new String(“x”)/时:
常量池的x,堆的new String(“x”)
-
new String(“yz”)时:
常量池的yz,堆的new String(“yz”)
-
new String(“x”) + new String(“yz”)时:
创建一个StringBuilder对象,调用append和toString在堆中生成一个new String(“x”) + new String(“yz”)对象(下面用new String(“xyz”)代替说明)
创建完后对象分别为:
- 常量池(2个对象):x, yz
- 堆(4个对象):new String("x") ,new String("yz"),StringBuilder, new String("xyz")
其他说明:
str为堆中new String(“xyz”)的引用
5. 一个引号加一个new
String str = "x" + new String("yz");
创建过程:
-
x时:
常量池的x
-
new String(“yz”)时:
常量池的yz,堆的new String(“yz”)
-
x + new String(“yz”)时:
创建一个StringBuilder对象,调用append和toString在堆中生成一个x+ new String(“yz”)对象(下面用new String(“xyz”)代替说明)
创建完后对象分别为:
- 常量池(2个对象):x, yz
- 堆(3个对象):new String(“yz”),StringBuilder, new String(“xyz”)
其他说明:
str为堆中new String(“xyz”)的引用
6. 两个变量相加
有变量引用的字符串是不能优化的,除非变量是final修饰,具体查看代码例子的问题八
String x = "x";
String yz = "yz";
String str = x + yz;
创建过程:
-
x时:
常量池的x
-
yz时:
常量池的yz
-
str = x + yz时:
创建一个StringBuilder对象,调用append和toString在堆中生成一个x + yz对象(下面用new String(“xyz”)代替说明)
创建完后对象分别为:
- 常量池(2个对象):x, yz
- 堆(2个对象):StringBuilder, new String(“xyz”)
其他说明:
str为堆中new String(“xyz”)的引用
参考链接:
https://blog.csdn.net/u013366617/article/details/83618361
代码例子