面试:String、StringBuilder以及StringBuffer

参考于:https://www.cnblogs.com/dolphin0520/p/3778589.html

String

  • 被final修饰

  • 大部分方法也被final修饰,反例有

CaseInsensitiveComparator 尽量不要说这个点,会引入 比较器排序知识点,未掌握

  • String对象的改变,不会影响原对象,而是创建新的对象,所以,String对象不建议经常变动,否则,会造成大量的运行时常量池内存浪费。

  • 每次String str = "zhangsan"生成,都会去常量池中查找"zhangsan",如果有,将地址值修改为原来内容的地址值;没有,那就单独开辟内存空间。

new关键字来生成对象是在堆区进行的,堆区进行对象生成的过程是不会去检测该对象是否已经存在的,所以每次String str = new String("zhangsan"),都是不同的新对象。即:凡是new出来的,正如字面意思,都是新对象。

String str1 = "hello world";String str2 = new String("hello world");String str3 = "hello world";String str4 = new String("hello world");
         
        System.out.println(str1==str2); falseSystem.out.println(str1==str3); trueSystem.out.println(str2==str4); false

在分析下面代码

public class Main {         public static void main(String[] args) {String string = "";for(int i=0;i<10000;i++){
            string += "hello";
        }
    }
}

为了更好的分析,我们先使用 javac Main.java

编译一下 Main.class 文件

接下来 就可以使用 javap Main.class 得到 注意观察 下面 变红的

Compiled from "Main.java"public class Main {  public Main();
    Code:       0: aload_0       1: invokespecial #1                  // Method java/lang/Object."<init>":()V   4: return

  public static void main(java.lang.String[]);
    Code:       0: ldc           #2                  // String   2: astore_1       3: iconst_0       4: istore_2       5: iload_2       6: sipush        10000   9: if_icmpge     38  12: new           #3                  // class java/lang/StringBuilder  15: dup      16: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V  19: aload_1      20: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  23: ldc           #6                  // String hello  25: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  28: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;  31: astore_1      32: iinc          2, 1  35: goto          5  38: return}

看到 是不是很扯淡?我没有写出来StringBuild,更没有调用append() 方法,别担心,这是 JVM 为了优化 减少性能浪费的。即便如次,我们也能看出来的1w,即:即便JVM 优化,依旧创建了1w个StringBuilder。你想想哪里优化了?其实是使用append()方法。 append()方法,会在原来的基础上修改原来的字符,返还This,不会造成大量的新常量池浪费,减少了gc次数,提高效率,但是创建了那么多的StringBuilder对象,效率还是不够高。

String对比StringBuilder

Builder拥有更好的性能,每次+操作,实际是在原来进行添加修改,减少常量池的损耗,为什么这么说,详细,往下看源码


StringBuilder  

@Overridepublic StringBuilder append(Object obj) {return append(String.valueOf(obj));
    }@Overridepublic StringBuilder append(String str) {super.append(str);return this;
    }

StringBuffer 
@Overridepublic synchronized StringBuffer append(Object obj) {
        toStringCache = null;super.append(String.valueOf(obj));return this;
    }@Overridepublic synchronized StringBuffer append(String str) {
        toStringCache = null;super.append(str);return this;
    }

你看,不管是StringBuilder,还是StirngBuffer,在使用append的时候,如果参数类型是String,那么直接相加,如果不是String的引用类型,那么就会先转为String,在进行相加。

所以,在大量相加字符串面前,不管是StringBuilder还是StringBuffer,性能都比String要好。

StringBuilder与StringBuffer对比。

因为Buffer中加入了 synchronized 关键字,这个关键字是在多线程访问时起到安全保护作用的。

所以,StringBuffer是线程安全的。

总而言之 :

不考虑线程安全 大量“加”操作的时候,builder > buffer >String

在线程安全下,大量使用“加”操作,只能使用buffer。

如果看完,还要问Buffer为什么比String要性能好,因为他是有append()方法。

文章版权声明:除非注明,否则均为八一构原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
AddoilApplauseBadlaughBombCoffeeFabulousFacepalmFecesFrownHeyhaInsidiousKeepFightingNoProbPigHeadShockedSinistersmileSlapSocialSweatTolaughWatermelonWittyWowYeahYellowdog
评论列表 (暂无评论,152人围观)

还没有评论,来说两句吧...

目录[+]

取消
微信二维码
微信二维码
支付宝二维码