学习了CSDN博主「Jalen Xu」的原创文章,对String中new和直接赋值的区别进行了总结
全为个人理解,还是浅薄
原链接:(https://blog.csdn.net/Xu_JL1997/article/details/89150026)
-
1.jdk1.6下,字符串池存放在jvm内存的方法区的永久代中;jdk1.7之后,字符串池存放在堆中,并且永久代被废除了
-
2.字符串池中存放的实际上还是字符串对象的引用,jdk1.7以前字符串池引用的对象放在方法区中,之后放到了堆中;
现在普遍使用jdk1.7上的版本,所以为了区分堆中被字符串池引用的对象和直接在堆中创建被其 他地方引用的对象,
以下均称堆中被字符串池引用的对象为字符串池中的对象 -
3.当直接对一个String类型赋值时,会先在字符串池中寻找是否存在和这个值相同的String对象,
如果没有,则在字符串池中创建这个对象,然后返回这个对象的引用;若寻找成功,则直接返回这个引用。
结论是这样的赋值方法可能创建0或1个对象 -
4.当使用new创建String对象时,肯定会在堆中创建一个对象,并且返回它的引用,
还会在字符串池中寻找是否存在和这个值相同的String对象,如果没有,则在字符串池中创建,有则不需创建。
结论是用这样的赋值方法可能创建1或2个对象 -
5.String是不可变对象,只要创建就不能修改,所有的修改操作实际上都相当于以直接赋值的方法创建String对象,当 a = “b”;后会到字符串池中寻找和"b"值相同的String对象,找到就返回它的引用,找不到就创建后再返回引用
-
6.额外注意的是,在jdk1.7废除了永久代后,String的intern()方法也做了相应修改:
jdk1.7以前inter()方法是在字符串池中寻找内容相同的对象,并返回引用,若找不到会在字符串中创建并返回;
jdk1.7后inter()方法在字符串池中找不到的话若堆中存在和其值相同的String对象,可以直接指向堆中的这个对象, 不需再在字符串池中创建对象
源码:
public class Difference {
public static void main(String[] args) {
Difference difference = new Difference();
//验证直接赋值和用new构建指向不同的对象,以及直接赋值指向的是字符串池中的对象
difference.d1();
//验证修改操作实际上相当于以直接赋值的方法在字符串池创建String对象
difference.d2();
//验证两个用new创建的“hello”,在堆中的String对象引用不同,但是在字符串池中的引用相同
difference.d3();
}
public void d1(){
String s1 = new String("hello");
String s2 = "hello";
System.out.println("s1 和 s2 指向同一个对象:"+(s1 == s2));//false
System.out.println("s1在字符串池中的引用和s2的引用相同:"+(s1.intern() == s2));//true
System.out.println("==========================================");
}
public void d2(){
String s1 = "hello";
String s2 = "hello";
System.out.println("s1 和 s2 的引用相同:"+(s1 == s2));//true
s1 = "he";
System.out.println("修改后的s1 和 s2(修改前的s1) 的字符串池引用相同:"+(s1.intern() == s2.intern()));//false
System.out.println("==========================================");
}
public void d3(){
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println("s1 和 s2 指向的是堆中的同一个对象:"+(s1 == s2));//false
System.out.println("s1 和 s2 在字符串池中的引用相同:"+(s1.intern() == s2.intern()));//true
System.out.println("==========================================");
}
}
输出结果:



