Java从入门到放弃 · String类详解(中)

273 阅读2分钟

“这是我参与8月更文挑战的第5天,活动详情查看: 8月更文挑战

上期我们讲了字符串具有共享的特点,那么它是如何实现共享的呢?这就是我们这期要讲的重点:字符串常量池

字符串常量池

对于字符串是java程序员经常要使用的对象,为了减少创建相同字符串对象的数量,JVM对此做了内存优化,在堆(Heap)中开辟出一块特殊的空间用来存放字符串常量,这块空间就叫做“字符串常量池”。

我们知道创建字符串对象有很多种方式,哪种方式创建的字符串才会被放入到常量池中呢?

答案是只有 String str = "abc"这种使用双引号直接创建的方式才可以。

我们先来看一道面试题:

String str1 = new String("abc");

问上面一行代码创建了几个对象?答案是两个。

一个是使用双引号创建的“abc”存放在常量池中。
另一个是new出来的对象存放在堆中。

可能到这里还不是特别明白,没关系,来看下一个常见的例子:

String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str2 == str3);

image.png 可以看到,str1等于str2,str1和str2都不等于str3,这里想必大家能够理解,上面已经讲过了,使用“”双引号直接创建的字符串被存放到常量池中。 对于String str1 = "abc";JVM会在常量池中首先寻找有没有和“abc”相等的字符串,如果没有则会在常量池中创建该字符串。对于String str2 = "abc";,显然常量池中已经有了该字符串,因此JVM会把“abc”的引用给str2,所以str1和str2具有相同的引用。显然第一个结果是true没问题。而使用new创建出来的字符串被保存在堆中,因此不具有相同的引用。

再来看下面的例子:

String str4 = "a";
String str5 = "b";
String str6 = "ab";
String str7 = str4 + str5;
String str8 = "a" + "b";
System.out.println(str6 == str7);
System.out.println(str7 == str8);
System.out.println(str6 == str8);

image.png 通过这个例子我们可以看出,str8在创建时,其实“a”和“b”并不存在,结果是“ab”。 而使用包含变量的字符串连接符创建的对象会存储在堆中,如str7。

结论:

1 使用“”双引号创建的字符串对象会被保存在常量池中。
2 使用字符串连接得到的字符串会被保存到常量池中,
3 使用new创建的字符串对象被保存在堆中。
4 使用包含变量创建的字符串对象也会被保存在堆中。
(这里需要注意的是,使用final修饰的变量相当于常量。)