浅谈StringBuilder拼接字符串和"+"拼接字符串的区别?

参考资料

Java 字符串拼接竟然有这么多姿势

如何看一段JAVA代码耗多少内存 - 最课程(zuikc.com)..._CSDN博客

 

前段时间上课的时候记得威哥讲到了关于StringBuilder的优势

(尽力还原,并非原话)

如下代码

String a="a";
String b="b";
String c="c";
​
System.out.println(a+b+c);

威哥对代码实际画图大概是这样的

 

浅谈StringBuilder拼接字符串和

(注意这是错误结论!)

 

 

用代码来解释就是

"a"+"b"+"c"; 的实质是

new StringBuilder(new StringBuilder("a").append("b").toString()).append("c").toString();

 

使用 "+" 拼接字符串 每一步都会在常量池创建一个新的字符串用来和后面的字符串拼接

虽然说String的拼接的确有时候效率很低,但是不至于内部代码睿智到这种程度

这句话在某些情况某些角度来讲的确是对的!

==========================以上是错误结论================================

 

以下是实践内容

 

所以威哥推荐我们在拼接字符串的时候不要使用

"a"+"b"+"c"这种形式

而使用new StringBuilder().append("a").append("b").append("c").toString();

然而这两种代码真的有区别嘛?

我写出以下代码测试

String a="a";
String b="b";
String c="c";
System.out.println(a+b+c);
System.out.println(new StringBuilder().append(a).append(b).append(c).toString());

导出编译成jar包后放入JAD反编译查看源码( IDEA我真的是不会用,导出搞了半天 )

然后得到了如下睿智的代码

String a = "a";
String b = "b";
String c = "c";
System.out.println(a + b + c);
System.out.println(a + b + c);

于是乎,放弃JAD改用java编译器自带的反编译

  javap -c                       对代码进行反汇编

得到了这段代码

Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return

public static void main(java.lang.String[]); Code: 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: ldc #4 // String c 8: astore_3 9: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 12: new #6 // class java/lang/StringBuilder 15: dup 16: invokespecial #7 // Method java/lang/StringBuilder."":()V 19: aload_1 20: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 23: aload_2 24: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: aload_3 28: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 31: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 34: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 37: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 40: new #6 // class java/lang/StringBuilder 43: dup 44: invokespecial #7 // Method java/lang/StringBuilder."":()V 47: aload_1 48: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 51: aload_2 52: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 55: aload_3 56: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 59: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 62: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 65: return }

左边是一大段的汇编代码看不懂,整理一下主要代码如下

// String a
// String b
// String c
​
// Field java/lang/System.out:Ljava/io/PrintStream;
// class java/lang/StringBuilder
// Method java/lang/StringBuilder."":()V
// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// Method java/lang/StringBuilder.toString:()Ljava/lang/String;
// Method java/io/PrintStream.println:(Ljava/lang/String;)V
​
// Field java/lang/System.out:Ljava/io/PrintStream;
// class java/lang/StringBuilder
// Method java/lang/StringBuilder."":()V
// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// Method java/lang/StringBuilder.toString:()Ljava/lang/String;
// Method java/io/PrintStream.println:(Ljava/lang/String;)V

是的,上下两段代码是完全一样的

生成一个StringBuilder对象,调用空参构造方法,然后执行三次append之后然后toString()

所以得出结论

"a"+"b"+"c"的代码最终被翻译成了new StringBuilder().append("a").append("b").append("c").toString();

根本不存在中间创建一个新的StringBuilder拼接字符串一说

 

那么StringBuilder相对于String之间的"+"拼接根本优势在于哪里?

这里参考了一篇CSDN关于字符串拼接讲的非常详解的文章

 

通俗的说一下大拿的讲解

String的"+"操作符比较适用于在一句话中进行的字符串拼接操作

而不适合在一个循环体结构中不断的拼接字符串,因为每一次for循环都会创建一个新的StringBuilder而

使用StringBuilder可以在循环体外面生成一个StirngBuilder然后每次只需要对相同的StringBuilder对象进行append操作

为什么阿里巴巴不建议在for循环中使用”+”进行字符串拼接

实际操作一下有了如下代码

Runtime runtime=Runtime.getRuntime();
        runtime.gc();;
        String a="";
        long startMemory=0;
        for(int i=0;i<9999;i++)
        {
            a+="a";
        }
        long endMemory=runtime.freeMemory();
        System.out.println("a: "+(endMemory-startMemory));
​
        String b="";
        StringBuilder builder=new StringBuilder();
        runtime.gc();
        startMemory=runtime.freeMemory();
        for(int i=0;i<9999;i++)
        {
            builder.append("b");
        }
        endMemory=runtime.freeMemory();
        System.out.println("b: "+(endMemory-startMemory));

实时查看一下JVM的freeMemory

注意两次计算间要用gc清理一下内存 (实际计算结果可能与操作系统环境有小偏差)

调用结果如下

a: 14177064
b: -183360

这里笔者也不太明白为什么第二个计算结果会是一个负数

不过结果显而易见 第一种"+"的拼接操作消耗了大量内存用于创建StringBuilder对象,用完就扔,无引用指向,留着浪费内存

综上所述

平时尽量能用StringBuilder(StringBuffer)就用,String的"+"可能更像是ENUM一样java给提供的语法糖.

by rzYork

如果有误 欢迎指错

你可能感兴趣的:(Java学习)