当前位置 博文首页 > yiguang_820的博客:String、StringBuffer、StringBuilder有什么
StringBuffer 和 StringBuilder 二者都继承了 AbstractStringBuilder ,底层都是利用可修改的char数组(JDK 9 以后是 byte数组)。
所以如果我们有大量的字符串拼接,如果能预知大小的话最好在new StringBuffer 或者StringBuilder 的时候设置好capacity,避免多次扩容的开销。扩容要抛弃原有数组,还要进行数组拷贝创建新的数组。
例子:
我们平日开发通常情况下少量的字符串拼接其实没太必要担心,例如
String str = "aa"+"bb"+"cc";
像这种没有变量的字符串,编译阶段就直接合成"aabbcc"了,然后看字符串常量池(下面会说到常量池)里有没有,有也直接引用,没有就在常量池中生成,返回引用。
如果是带变量的,其实影响也不大,JVM会帮我们优化了。(以下运行JDK版本为1.8)
看看反编译结果,String拼接用的是StringBuilder.append。
是不是好像觉得那不平时不需要用StringBuilder 啊,用String就好了啊,都帮我们优化了?
不是的来看这个情况
看看反编译结果,new了很多次StringBuilder
也就是说会如果有大量的字符串拼接new好多StringBuilder对象,所以频繁的字符串操作还是得用StringBuilder!
再说说字符串常量池
看看我们的代码,你会发现String是真的频繁得使用到,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池。
创建一个字符串时,首先会检查池中是否有值相同的字符串对象,如果有就直接返回引用,不会创建字符串对象;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。但是,通过new方法创建的String对象是不检查字符串常量池的,而是直接在堆中创建新对象,也不会把对象放入池中。上述原则只适用于直接给String对象引用赋值的情况。
String str1 = new String("a"); //不检查字符串常量池的
String str2 = "bb"; //检查字符串常量池的
String还提供了intern()方法。调用该方法时,如果字符串常量池中包括了一个等于此String对象的字符串(由equals方法确定),则返回池中的字符串的引用。否则,将此String对象添加到池中,并且返回此池中对象的引用。
在JDK6中,不推荐大量使用intern方法,因为这个版本字符串缓存在永久代中,这个空间是有限了,除了FullGC之外不会被清楚,所以大量的缓存在这容易OutOfMemoryError。
之后的版本把字符串放入了堆中,避免了永久代被挤满。
总结
如果错误欢迎指正
cs