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
可以看出先创建了一个“aaa”字符串,然后当a遇到+=时,创建了一个StringBuilder对象,并append了aaa字符串。之后创建了一个“bbb”对象,然后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
猜你喜欢
- [LeetCode] 131.Palindrome Partitioning 拆分回文串Given a string s, par
- using System.Runtime.InteropServices; using System.Text; publicclass F
- 一、概述xml整合第三方框架有两种整合方案:不需要自定义名空间,不需要使用Spring的配置文件配置第三方框架本身内容,例如:MyBatis
- 本文实例讲述了winform中的ListBox和ComboBox绑定数据用法。分享给大家供大家参考。具体实现方法如下:本例实现将集合数据绑定
- 一. 析构方法1. 概念我们现在已经知道,构造方法负责创建一个Java的类对象,并可以对该对象进行初始化。与此相对应的,其实还有一个方法,可
- 1.MyBatisX插件在使用mybatis或者mybatis-plus时,我们可以安装IDEA的MyBatis的插件 - MyBatisX
- LRU算法:最近最少使用淘汰算法(Least Recently Used)。LRU是淘汰最长时间没有被使用的缓存(即使该缓存被访问的次数最多
- 首先理解数据绑定为什么要使用数据绑定基于HTTP特性,所有的用户输入的请求参数类型都是String,比如下面表单:但我们提交后,为了将请求信
- 1. 测试文档、期望达到的目标文档效果用于测试的Word文档如下所示,包含的空白段落影响文章整体布局及美观性:目标文档效果:2. 辅助工具2
- C#串口模块的使用。使用VS .net框架下WinForm程序应用开发。C#开发的串口通信小工具。相比于QT添加的串口类,WinForm是通
- bean 的生命周期对象创建实例化Bean对象,默认选择无参构造方法,如果只有一个有参构造那么调用有参构造,如果只有多个有参构造那么报错,除
- 先直接看看效果吧初始情况 点击一个作为标记 再次点击后删除 3.这里还要感谢前辈的代码作为参考,毕竟以前也没有写过关于日历方面的东西,别人确
- 前言最近在改进项目的并发功能,但开发起来磕磕碰碰的。看了好多资料,总算加深了认识。于是打算配合查看源代码,总结并发编程的原理。准备从用得最多
- 微服务治理Spring Cloud 工具套件为微服务治理提供了全面的技术支持。这些治理工具主要包括服务的注册与发现、负载均衡管理、动态路由、
- SpringBoot如何快速配置数据源;有如下两种方式:通过spring-boot-starter-jdbc快速配置数据源自定义数据源Dat
- 实现从数据库中动态获取对应的List集合,并在Easyui的combobox中显示出来。实现的效果如下:1、数据库的表设计如图所示2、数据库
- 一 . 得到这个对象的实例Connection con ;con = DriverManager.getConnection(url,use
- 这篇文章主要介绍了Java中的3种输入方式实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可
- //Annotation configuration dwr servletprivate void initializeDwrServle
- 本文实例讲述了Android判断网络类型的方法。分享给大家供大家参考,具体如下:判断网络类型是wifi,还是3G,还是2G网络,对不同的网络