关于Java中字符串的存储方式 - Alias的博客

关于Java中字符串的存储方式

创建方式1:

1
String s = "123";

首先在栈中创建字符串”123”,随后调用intern(),检查字符串常量池中是否存在对这个字符串的引用,如果有则返回对他的引用,没有的话则将这个字符串存入字符串常量池。如果改字符串已经存储在堆中,intern方法会直接将其引用到字符串常量池中

s返回的是字符串常量池中”123”的引用

创建方式2:

1
String s=new String("123");

这个语句会将”123”放入字符串常量池,在队中创建一个字符串对象,里面的值和常量池中的一样,返回引用

因此会创建两个对象,而引用指向堆中的对象

创建方式3:

1
String s=new String("1")+new String("23");

这种方式底层等价于用StringBuilder进行拼接,其最大的区别就是不会在字符串常量池中创建对象,而是只在堆中创建并返回其引用

一些场景

场景一

1
2
3
String s1 = "123";
String s2 = s1.intern();
System.out.println(s1 == s2);

返回为true,因为s1为常量池中”123”的引用,s2返回的也是常量池中”123”的引用,所以返回为true

1
2
3
String s1 = new String("123");
String s2 = s1.intern();
System.out.println(s1 == s2);

这种情况,s2和上面相同,但s1为堆中对象的引用,所以为false

场景二

1
2
3
4
5
6
7
String h = new String("hw");
String h2 = h.intern();
String h1 = "hw";

System.out.println(h == h1);
System.out.println(h2 == h1);
System.out.println(h2 == h);

h为堆中对象的引用,h2为字符串常量池中对象的引用,h1也是

字符串常量池中对象的引用,所以答案为false,true,false

1
2
3
4
5
6
7
String s = new String("1") + new String("1");
String s2 = s.intern();
String s1 = "11";

System.out.println(s == s1);
System.out.println(s2 == s1);
System.out.println(s2 == s);

s为堆中对象的引用,s2由于字符串常量池中不存在对象,所以将调用字符串的引用存入进去,所以s2还是堆中对象的引用,s1在创建时因为字符串常量池中已经有了该对象,所以直接返回该对象的引用,而该对象的引用对应的是堆中对象,所以s,s1,s2得到的是同一个引用,所以为true,true,true

场景三

1
2
3
4
5
6
7
String s = new String("1") + new String("1");
String s1 = "11";
String s2 = s.intern();

System.out.println(s == s1);
System.out.println(s2 == s1);
System.out.println(s2 == s);

s为堆中对象的引用,s1在字符串常量池中创建对象并返回引用,s2返回的是s1的引用,所以为false,true,false

评论