Java中字符串String的+和+=及循环操作String原理详解

作者:LJHSkyWalker 时间:2023-05-13 15:10:35 

String对象是不可变的:意思就是无论是对String的新增或修改,出现一个全新的String内容时,都意味着诞生了一个新的对象。但是如果内容不变的话,增加的只是对象的引用而已。

例如:

String a = "ljh";
String b = "ljh";
String c = "ljh";

System.out.println(a==b);
System.out.println(b==c);

结果都是true

但是这种不可变性会产生一些性能上的问题,所以JVM对String对象重载“+”“+=”进行了一些优化

操作符“+”可以用来连接String

String aaa = "ljh";
String bbb = "big";
String ccc = aaa+bbb+"aaaa";

在jdk8中,上述代码中在底层其实是编译器擅自调用了StringBuilder类进行+的操作,主要原因是StringBuilder的append()更加高效,我们来看一下字节码。

public static void main(java.lang.String[]);
   Code:
      0: ldc           #2                  // String ljh
      2: astore_1
      3: ldc           #3                  // String big
      5: astore_2
      6: new           #4                  // class java/lang/StringBuilder
      9: dup
     10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
     13: aload_1
     14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     17: aload_2
     18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     21: ldc           #7                  // String aaaa
     23: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     29: astore_3
     30: return

可以看出一共有四个对象,分别是三个String 和一个StringBuilder

我们再来看一下+=

String a = "aaa";
a += "bbb";

字节码如下

    Code:
       0: ldc           #2                  // String aaa
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String bbb
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: return

可以看出先创建了一个&ldquo;aaa&rdquo;字符串,然后当a遇到+=时,创建了一个StringBuilder对象,并append了aaa字符串。之后创建了一个&ldquo;bbb&rdquo;对象,然后append了bbb字符串,最后调用StringBuilder的toString方法。

接下来再看看循环中调用+=会是什么样子

String a = "aaa";
a += "bbb";
for(int i=0;i<5;i++){
   a+="ccc";
}

    Code:
       0: ldc           #2                  // String aaa
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String bbb
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: iconst_0
      24: istore_2
      25: iload_2
      26: iconst_5
      27: if_icmpge     56
      30: new           #3                  // class java/lang/StringBuilder
      33: dup
      34: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      37: aload_1
      38: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      41: ldc           #8                  // String ccc
      43: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      46: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      49: astore_1
      50: iinc          2, 1
      53: goto          25
      56: return

可以看出先创建String对象aaa,之后创建StringBuilder并初始化StringBuilder append aaa,然后创建bbb对象,并append(  bbb),然后我们发现在循环中依旧创建了一个新的StringBuilder,也就是没经过一次循环都要创建一个新的StringBuilder对象。

这时我们做一个优化,提前创建StringBuilder对象

String a = "aaa";
a += "bbb";
StringBuilder sb = new StringBuilder(a);
for(int i=0;i<5;i++){
   sb.append("ccc");
}

    Code:
       0: ldc           #2                  // String aaa
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String bbb
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: new           #3                  // class java/lang/StringBuilder
      26: dup
      27: aload_1
      28: invokespecial #8                  // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      31: astore_2
      32: iconst_0
      33: istore_3
      34: iload_3
      35: iconst_5
      36: if_icmpge     52
      39: aload_2
      40: ldc           #9                  // String ccc
      42: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      45: pop
      46: iinc          3, 1
      49: goto          34
      52: return

可以看出循环体跳回34行,并不会不断地创建新的StringBuilder,大大提高了效率和减小了垃圾数量!,所以我们要注意自己的写法!避免无谓的消耗

来源:https://blog.csdn.net/qq_31615049/article/details/80891142

标签:string字符串,+,+=
0
投稿

猜你喜欢

  • C#使用iTextSharp设置PDF所有页面背景图功能实例

    2021-10-26 02:01:59
  • 详解kotlin中::双冒号的使用

    2022-09-04 10:17:23
  • 一文带你熟练掌握Java中的日期时间相关类

    2022-01-21 00:42:54
  • Java web spring异步方法实现步骤解析

    2023-12-19 03:14:58
  • Android实现圆形渐变加载进度条

    2021-07-17 18:38:06
  • 基于Java Springboot + Vue + MyBatis实现音乐播放系统

    2023-07-09 16:01:41
  • Java PreparedStatement用法详解

    2023-08-08 20:20:51
  • 基于标准http实现Android多文件上传

    2023-05-28 05:55:28
  • Android调试华为和魅族手机logcat不显示的问题

    2023-12-06 04:17:55
  • C#访问SqlServer设置链接超时的方法

    2022-11-19 17:43:21
  • IntelliJ IDEA中显示和关闭工具栏与目录栏的方法

    2023-09-01 23:18:59
  • 一文带你认识Java中的Object类和深浅拷贝

    2023-02-05 16:52:08
  • 基于spring AOP @Around @Before @After的区别说明

    2023-12-15 03:08:25
  • Java编程中ArrayList源码分析

    2023-05-20 00:05:25
  • 适配android7.0获取文件的Uri的方法

    2022-03-13 17:32:06
  • c# 实现KMP算法的示例代码

    2023-12-02 06:35:19
  • OpenGL Shader实现阴影遮罩效果

    2022-04-23 19:38:02
  • Android中ACTION_CANCEL的触发机制与滑出子view的情况

    2023-08-01 14:39:09
  • spring-cloud入门之eureka-client(服务注册)

    2023-12-16 22:42:51
  • Java原生服务器接收上传文件 不使用MultipartFile类

    2023-11-09 19:31:36
  • asp之家 软件编程 m.aspxhome.com