Java基础(一)-String详解
由于网上关于String的介绍鱼目混杂,在这里记录下自己的理解,代码基于JDK1.8
以下将字符串常量池简称为池
一、new String创建了几个对象?
//情景1 String str="hello wrold"; String str2=new String("hello world")//这行代码创建了一个对象 //情景2 String str4=new String("abcd");//这行代码创建了2个对象 String str3="abcd";
分析:
情景1:由于在new创建对象之前,池中已存在字符串常量,并且符号引用str指向"hello wrold";在new创建对象时,只需要在堆中创建String对象即可
情景2:由于在new创建对象之前,池中不存在字符串"hello world",所以在调用new创建对象时,会在堆中创建String对象,在池中创建一个对象,但是符号引用str3指向堆中的对象;
在测试之前引入intern()方法,在《深入理解Java虚拟机》中周老师这样介绍:它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
String str=new String("hello")+new String(" world");//创建了5个对象,池中:"hello"、" world"、堆中:"hello"," world","hello world" str.intern();//池中没有"hello world",所以在池中添加"hello world"并保存str的符号引用 String str2="hello world";//池中已经存在,返回str的符号引用 System.out.println(str==str2);//ture String str3=new String("aa")+new String("bb");//分析同上 String str4="aabb"; str3.intern();//池中已存在"aabb" System.out.println(str3==str4);//false
output:


中间还有个小细节需要注意:
代码如下
String str=new String("hello world"); String str2=new String("hello")+new String(" world");
只思考"hello world"对象,其他忽略
第一行代码在池中、堆中都创建了"hello wrold"对象
第二行代码只在堆中创建了"hello world"对象
二、字符串常量池及运行时常量池在JVM中的位置
在JDK1.6时,字符串常量池与运行时常量池都存在于永久代中;
在JDK1.7之后,字符串常量池从永久代中拿了出来,放在堆中;运行时常量池仍然放在永久代;
在JDK1.8之后,删除了永久代,引入了元空间;所以运行时常量池放在了元空间中。
三、字符串拼接的理解
使用"+"对字符串拼接时,是调用StringBuilder对象的append()方法拼接之后调用toString()方法转换为String对象;而且Java编译字符串时会进行优化,如果字符串在编译期可确定,那么会放在池中;如果无法确定,那么会调用append()方法拼接。
String str="a"; String str2="a"+str;//在池中创建"a",堆中创建"aa" str2.intern(); String str3="aa"; System.out.println(str2==str3);//true
output:
如果有不同见解,欢迎讨论
参考文献:
java面试题之----String的intern:https://www.cnblogs.com/xuxinstyle/p/9526210.html