几个核心问题
- intern方法
- 字符串常量池、class常量池和运行时常量池
- equals方法
- 创建String的不同方式,其对象的保存和创建过程
- 线程安全问题以及不可变性
- StringBuffer和StringBuilder
创建字符串的方式
String s1="hi";
String s2=new String("hi");
不同创建方式的创建过程:
- 字面值的方式:使用双引号会在字符串常量池中寻找是否已经存在 “hi” 这个字符串,如果有则直接返回该对象的引用,如果没有则在字符串常量池创建该String对象,并返回引用。
- new的方式:凡是使用new,都会在堆中创建一个对象,此处会在堆中创建一个"hi"对象,此处new一个String对象时,先去字符串常量池查看是否存在"hi",如果有,则不用再字符串常量池中创建,只需要在堆中创建该对象,并且返回堆中对象的引用。
s1==s2 //true or false?
s1.equals(s2); //true or false?
第一个结果肯定是false,首先==比较的是引用。从上述来看,双引号返回的是字符串常量池中的引用,new返回的是堆中的引用。
第二个结果则是true,String对equals方法进行重写,首先会比较二者的类型是否相同,都为String,然后再比较二者的内容是否相同,都为"hi"。则返回true。
编译器对于字面量方式创建String的优化
String str="a"+"b"; //直接由编译器优化为 String str="ab";
String str1="c";
String str2=str1+str2; //实际上会创建一个StringBuilder对象,并且调用其append方法进行拼接字符串,最后调用StringBuilder的toString方法
示例代码:
public class Hello {
public static void main(String[] args) {
String s1="Tom";
String s2=new String("Bob");
String s3="a"+"b";
String s4=s1+s3;
System.out.println(s3);
}
}
反编译字节码:
new String()创建了几个对象?
在1.7之后,new出来的String对象会创建在堆中,而字符串常量池中只是保存的引用,无需再创建一个对象。
intern方法
方法描述:
intern方法返回字符串在字符串常量池中的引用,如果存在该字符串,则直接返回,否则创建该对象后再返回它的引用。
s2.intern()==s1; //true
或者这样写
String s3 = s2.intern():
s3==s1; //true
目前理解是,字符串常量池中存放的有对象和引用两种。
这里有一篇讨论的文章,还未弄明白。
https://blog.csdn.net/weixin_39460458/article/details/79982765?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
String s3 = "A";
String s4 = "B";
String s5=s3+s4;
System.out.println(s5.intern()==s5); //true
字符串常量池
文章内容来自我之前查询相关博客的总结和思考,当时也没有留下链接。如有侵权请联系,我会进行相应删除。