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

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,大大提高了效率和减小了垃圾数量!,所以我们要注意自己的写法!避免无谓的消耗

总结

到此这篇关于Java中字符串String的+和+=及循环操作String原理的文章就介绍到这了,更多相关Java字符串String+和+=内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript 利用StringBuffer类提升+=拼接字符串效率

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv=&qu

  • java中synchronized(同步代码块和同步方法)详解及区别

     java中synchronized(同步代码块和同步方法)详解及区别 问题的由来: 看到这样一个面试题: //下列两个方法有什么区别 public synchronized void method1(){} public void method2(){ synchronized (obj){} } synchronized用于解决同步问题,当有多条线程同时访问共享数据时,如果进行同步,就会发生错误,Java提供的解决方案是:只要将操作共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他

  • 关于java中可变长参数的定义及使用方法详解

    JAVA中可以为方法定义可变长参数( Varargs)来匹配不确定数量的多个参数,其定义用"..."表示.其实,这类似于为方法传了一个数组,且在使用方法上也和数组相同,如下: public void test(String... str){ for(String s : str){ } } 调用方法就像普通的调用方式相同,只不过可以匹配的参数为0到多个.如下: test(); test("lilei"); test("lilei","h

  • Java 中桥接模式——对象结构型模式的实例详解

    Java  中桥接模式--对象结构型模式的实例详解 一.意图 将抽象部分与它的实现部分分离,使他们都可以独立的变化. 二.适用性 以下一些情况使用Bridge模式 你不希望在抽象和它的实现部分之间有一个固定的绑定关系.例如这种情况可能因为,在程序运行时刻实现部分应可以被选择或者切换. 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充.这时Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对他们进行扩充. 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译

  • Java中SSM框架实现增删改查功能代码详解

    记录一下自己第一次整合smm框架的步骤. 参考博客和网站有:我没有三颗心脏 How2J学习网站 1.数据库使用的是mySql,首先创建数据库ssm1,并创建表student create database ssm1; use ssm1; CREATE TABLE student( id int(11) NOT NULL AUTO_INCREMENT, student_id int(11) NOT NULL UNIQUE, name varchar(255) NOT NULL, age int(1

  • java中的前++和后++的区别示例代码详解

    java中的前加加++和后加加++,有很多人搞的很晕,不太明白!今天我举几个例子说明下前++和后++的区别! 其实大家只要记住一句话就可以了,前++是先自加再使用而后++是先使用再自加! 前++和后++总结:其实大家只要记住一句话就可以了,前++是先自加再使用而后++是先使用再自加! 请大家看下面的例子就明白了! public class Test { public static void main(String[] args) { //测试,前加加和后加加 //前++和后++总结:其实大家只要

  • Java  中桥接模式——对象结构型模式的实例详解

    Java  中桥接模式--对象结构型模式的实例详解 一.意图 将抽象部分与它的实现部分分离,使他们都可以独立的变化. 二.适用性 以下一些情况使用Bridge模式 你不希望在抽象和它的实现部分之间有一个固定的绑定关系.例如这种情况可能因为,在程序运行时刻实现部分应可以被选择或者切换. 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充.这时Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对他们进行扩充. 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译

  • Java中==与equals()及hashcode()三者之间的关系详解

    目录 1.= = 2.equals() 3.重写equals() 4.equals()比较流程 5.hashcode() 1.= = =为赋值运算符,==为比较运算符,仅比较对象的内存地址,无法比较真正意义上的相等! JDK里的equals方法就是通过==来实现的比较对象的内存地址 以Integer为例 Integer a = 127; Integer b = 127; System.out.println(a == b);//true Integer c = 128; Integer d =

  • Kotlin中的惰性操作容器Sequence序列使用原理详解

    目录 Sequence序列 执行的顺序 只做最少的操作 序列可以是无限的 序列不会在每个步骤创建集合 Sequence的基本使用 序列的创建 序列的操作 Sequence源码分析 Sequence是什么? 序列的创建方式分析 序列的惰性原理 总结 Sequence序列 Sequence 是Kotlin标准库提供的一种容器类型.它和Iterable一样具备对集合进行多步骤操作能力,但是却是采用了一种完全不同于Iterable的实现方式: val map = (0..3).filter { prin

  • Java中的拦截器、过滤器、监听器用法详解

    本文实例讲述了Java中的拦截器.过滤器.监听器用法.分享给大家供大家参考,具体如下: 一.拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方 法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作. 1.Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,

  • Java中char[]输出不是内存地址的原因详解

    前言 Java中共有八种基本数据类型:byte,int,short,long,float,double,char,boolean. 计算机中的基础数据单位是bit, 1byte=8bit. 数据类型 存储大小 举例 注释 包装类 byte 1byte 3 字节 Byte int 4byte 4 整数 Integer short 2bytes 5 短整数 Short long 8bytes 6 长整数 Long float 4bytes 1.3 单精度浮点型 Float double 8bytes

随机推荐