1、了解常量池
字符串常量池中存储的就是各种字符串,在常量池中这些字符串都是唯一的。字符串常量池中存储的是在编译期就确定的,存在.class文件中的字符串常量。字符串常量池能有效地减少内存开销,毕竟程序中出现相同的字符串是很大概率的事情,如果为每个字符串都去开辟内存空间,后果可想而知。
2、内存分析
1、创建String的基本方式
String s1 = "abc";
String s2 = new String("abc");
- String s1 = "abc" 创建过程:先去常量池中查找是否有"abc"这个字符串,如果有,则直接返回引用给s1,没有的话在在常量池中创建"abc",并返回引用给s1。"abc"是一个字符串,直接把字符串赋给一个变量,这在编译期就可以确定。
-
String s2 = new String("abc")创建过程:先在堆中创建一个"abc"对象(当然个人认为这不是在将"abc"直接存在堆中),在常量池中查找是否有"abc"。如果有,则让堆中的"abc"对象直接指向常量池中的"abc"。如果没有,则在常量池中创建"abc",并使堆中的"abc"对象直接指向常量池中的"abc"。
image.png
这个图之前在网上也是有看过的,不过关于new String(),网上有许多的说法,这个图也是经过实验得出来的,下面上实验过程。
class Person{
String name;
public Person(String name){
this.name = name;
}
}
public class StringHeapTest {
public static void main(String[] args) {
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2); //false,s1指向常量池,s2指向堆中,所以地址不同
Person p1 = new Person("xiaoming");
Person p2 = new Person("xiaoming");
System.out.println(p1.name == p2.name); //true,堆中地址都指向常量池中的"xiaoming"
}
}
结论:通过String a = "a"
;方式创建的String对象,一般情况下栈中变量直接指向常量池(String.intern()方法可能会影响结果)。
String a = new String
方式创建的String对象,栈中变量指向堆中,堆中对象中存储这该字符串在常量池中地址,由堆中在指向常量池。所以我们看到的直接字符串赋值和new String()出来的地址是不同的,堆中两个Person对象的name属性,它们的地址是相同的,都是指向常量池中"xiaoming"。
2、String拼接
String s1 = "a" ;
String s2 = "abc"
String s3 = s1 + "bc";
网友评论