java String常量池与字符串拼接性能优化

----String常量池----
1.常量池中的对象从哪里来的?

String s1="hanhan";
String s2="hanhan";
System.out.println(s1==s2);//true

当我们创建String对象采用字面量形式时,JVM首先会对这个字面量进行检查,如果常量池中存放有该字面量,则直接使用,否则创建新的对象并将其引用放入常量池中。

String s1="han";
String s2=new String("han");
System.out.println(s1==s2);//false

当我们通过new来创建一个字符串时,JVM就不会去常量池中找,而是直接在堆中新建一个对象。如果我们想把new的对象也放在常量池中,可以调用方法inner();

String s1="guoguo";
String s2=new String("guoguo").intern();
System.out.println(s1==s2);//true

当我们new新的对象时,之后再调用intern()方法,如果没有把s2重新引用则s2仍为原来的对象,此时s1不等于s2,若重新引用常量池中的对象,则s1等于s2
这里写图片描述

String s1="gh";
String s2=new String("gh");
s2.intern();
System.out.println(s1==s2);//false;
s2=s2.intern();
System.out.println(s1==s2);//true;

2.常量池中存的是对象还是引用?
常量池中存的是对对象的引用,存储于JVM的方法区中,而且引用的对象存储于堆中。
3.常量池中的对象会被GC回收吗?
当常量池中的引用没有被任何变量引用时,就会被GC回收!
这里写图片描述

----字符串拼接----
1.字符串拼接的内部实现

String s1="a"+"b"+"c";

正常情况下,执行声明s1代码会生成3个对象,即对象a、对象ab、对象abc,其中对象a和对象ab都是中间的临时变量,最后的对象abc才赋值给了s1。因此在使用字符串拼接的时候,拼接的数量越多,性能越低!
但是java编译器在编译的时候做了优化,在编译时新建一个对象StringBuilder来拼接,这样就避免了产生很多临时对象,从而提升了性能!但是一下代码性能就低下:

String s="";
for(int i=0;i<length;i++){
   s+=i;
}

之所以低下的原因是因为循环内,每次都在做字符串拼接,每次都在产生一个StringBuilder对象,造成内存的浪费!因此这种错误要尽量避免,稍做以下优化即可完美改造:

String s="";
StringBuilder sb=new StringBuilder();
for(int i=0;i

以上代码通过在循环为new一个StringBuilder对象来拼接,这样就避免了循环中创建对象了!

2.字符串拼接的性能优化
通过以上案例,我们就已经知道了字符串拼接时尽量使用StringBuilder或者StringBuffer对象,特别时循环中的拼接!

3.StringBuilder与StringBuffer的区别
两者的共同点都是建立一个字符串缓冲区,然后调用相关方法操作字符串!不同点就是StringBuilder是非同步的,而StringBuffer是同步的,因此StringBuilder执行效率更高,在不需要同步的情况下优先使用StringBuilder,否则使用StringBuffer来保证数据的同步,即多线程的情况下!

更多参考:
字符串常量池介绍
字符串拼接细节分析
interned Strings : Java Glossary

你可能感兴趣的:(java基础,string,java)