String字符串相加的问题

前几天同事跟我说我之前写的代码中在操作字符串时候,使用字符串相加的方式而不是使用StringBuffer或者StringBuilder导致内存开销很大。这个问题一直在困扰我,因为在《Think in java》一书中,作者说使用“+”拼接字符串并不比StringBuffer或者StringBuilder效率低下,因为“+”是java唯一一个系统级的针对字符串的重载过的操作符。

大家都知道String是一个final修饰的类。那么两个字符串使用“+”相加到底会不会导致字符串操作效率受到影响呢?

下面是书中和牛人的理解的结合:

用bytecode来说明问题:

1.使用String + 的方式:
public class Test2 {
    public static void main(String[] args) {
        String a = "a";
        String b = "b";
        String c = "c";
        String s = a + b + c;
    }
}

【同时揭示了为何变量相加时 与常量池中的“abc”不相等  因为相加变量本质上是一个StringBuilder对象】

对应的bytecode为:

public class Test2 extends java.lang.Object{
public Test2();
  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 a
   2:   astore_1
   3:   ldc     #3; //String b
   5:   astore_2
   6:   ldc     #4; //String c
   8:   astore_3
   9:   new     #5; //class StringBuffer
   12:  dup
   13:  invokespecial   #6; //Method java/lang/StringBuffer."<init>":()V
   16:  aload_1
   17:  invokevirtual   #7; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   20:  aload_2
   21:  invokevirtual   #7; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   24:  aload_3
   25:  invokevirtual   #7; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   28:  invokevirtual   #8; //Method java/lang/StringBuffer.toString:()Ljava/lan
g/String;
   31:  astore  4
   33:  return

}

2.使用StringBuffer.append()的方式:
public class Test3 {
    public static void main(String[] args) {
        String a = "a";
        String b = "b";
        String c = "c";
        StringBuffer sb = new StringBuffer();
        sb.append(a).append(b).append(c);
        String s = sb.toString();
    }
}

对应的bytecode为:

public class Test3 extends java.lang.Object{
public Test3();
  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 a
   2:   astore_1
   3:   ldc     #3; //String b
   5:   astore_2
   6:   ldc     #4; //String c
   8:   astore_3
   9:   new     #5; //class StringBuffer
   12:  dup
   13:  invokespecial   #6; //Method java/lang/StringBuffer."<init>":()V
   16:  astore  4
   18:  aload   4
   20:  aload_1
   21:  invokevirtual   #7; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   24:  aload_2
   25:  invokevirtual   #7; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   28:  aload_3
   29:  invokevirtual   #7; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   32:  pop
   33:  aload   4
   35:  invokevirtual   #8; //Method java/lang/StringBuffer.toString:()Ljava/lan
g/String;
   38:  astore  5
   40:  return

}

看到了么?后者不光不比前者效率高,反而多了一些临时变量的存取

至于推荐用StringBuffer来代替String+拼装字符串,说的是循环方式下,如:

public class Test4 {
    public static void main(String[] args) {
        String s = "s";
        for (int i = 0; i < 20; i++) {
            s += i;
        }
    }
}

对应的bytecode为:

public class Test4 extends java.lang.Object{
public Test4();
  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 s
   2:   astore_1
   3:   iconst_0
   4:   istore_2
   5:   iload_2
   6:   bipush  20
   8:   if_icmpge       36
   11:  new     #3; //class StringBuffer
   14:  dup
   15:  invokespecial   #4; //Method java/lang/StringBuffer."<init>":()V
   18:  aload_1
   19:  invokevirtual   #5; //Method java/lang/StringBuffer.append:(Ljava/lang/S
tring;)Ljava/lang/StringBuffer;
   22:  iload_2
   23:  invokevirtual   #6; //Method java/lang/StringBuffer.append:(I)Ljava/lang
/StringBuffer;
   26:  invokevirtual   #7; //Method java/lang/StringBuffer.toString:()Ljava/lan
g/String;
   29:  astore_1
   30:  iinc    2, 1
   33:  goto    5
   36:  return

}

如果用String+的方式,每循环一次,就会重新new一个StringBuffer对象,这样的内存消耗完全是不必要的(在数据量大的情况下,还会导致内存不足的错误),所以要这样做:

public class Test5 {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("s");
        for (int i = 0; i < 20; i++) {
            sb.append(i);
        }
    }
}
这样无论循环多少次,都只会生成一个StringBuffer对象

回想下代码,我确实是在循环中使用了“+”,而且循环次数还不少,同事说的没错,改为StringBuffer就快多了。特此记下。

【转】String字符串相加的问题的更多相关文章

  1. String 字符串相加比较

    String 字符串相加 对比 public static void main(String[] args) { String a = "helloword"; final Str ...

  2. String字符串相加的原理

    因为String是非常常用的类, jvm对其进行了优化, jdk7之前jvm维护了很多的字符串常量在方法去的常量池中, jdk后常量池迁移到了堆中 方法区是一个运行时JVM管理的内存区域,是一个线程共 ...

  3. String字符串相加常见面试题

    String name1="jack"; String name2="jack"; System.out.println(name1==name2); // t ...

  4. C语言关于利用sscanf实现字符串相加减

    #include<stdio.h>#include<string.h>void main(){ int a; int b; char str1[10] = "9999 ...

  5. java中String字符串的==解析

    今天不知道怎么看了下string的==的问题,本身我觉得我这个水平去判断几个字符串相等还能出问题?呵呵,真的出了大问题,根本原因在于对java字节码的不了解. 首先,==运算符比较的是两个变量所指向的 ...

  6. 代码题(59)— 字符串相加、字符串相乘、打印最大n位数

    1.415. 字符串相加 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和. 思路:和链表相加类似,求进位. class Solution { public: string addS ...

  7. Java中String字符串toString()、String.valueOf()、String强转、+ ""的区别

    Object#toString(): Object object = getObject(); System.out.println(object.toString()); 在这种使用方法中,因为ja ...

  8. LeetCode:字符串相加【415】

    LeetCode:字符串相加[415] 题目描述 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和. 注意: num1 和num2 的长度都小于 5100.num1 和num2 都只 ...

  9. String字符串性能优化的几种方案

    String字符串是系统里最常用的类型之一,在系统中占据了很大的内存,因此,高效地使用字符串,对系统的性能有较好的提升. 针对字符串的优化,我在工作与学习过程总结了以下三种方案作分享: 一.优化构建的 ...

随机推荐

  1. redis集群搭建及注意事项

    上一篇:redis的安装及注意事项 这里,在一个Linux虚拟机上搭建6个节点的redis伪集群,思路很简单,一台虚拟机上开启6个redis实例,每个redis实例有自己的端口.这样的话,相当于模拟出 ...

  2. Spring MVC控制层传递对象后在JSP页面中的取值方法

    List<Order> orders = new ArrayList<Order>(); for (int i = 0; i < 3; i++) { Order t = ...

  3. android如何与asp.net服务端共享session

    近期需要实现一个功能,就是需要通过发送短信进行注册,现在想把短信验证码放到服务器的session值中,当客户端收到短信并提交短信码时由asp.net服务端进行判断,那么如何共享这个session那么需 ...

  4. django下进行项目的部署

    -------------------Django下进行对应的服务器配置1.服务器购买 本人在阿里云购买了一个服务器,操作系统为windows server2008/Linux(ubuntu) 2.服 ...

  5. 深入理解JVM(八)——java堆分析

    上一节介绍了针对JVM的监控工具,包括JPS可以查看当前所有的java进程,jstack查看线程栈可以帮助你分析是否有死锁等情况,jmap可以导出java堆文件在MAT工具上进行分析等等.这些工具都非 ...

  6. Topshelf便捷创建Windows服务

    结合Quartz.net学习,前提已经创建了一个定时任务,可见 <定时调度框架:Quartz.net> (基于配置文件形式) 首先引用Topshelf.dll 自定义服务TestServi ...

  7. 使用设置sa用户登录sql server2008

    今天在net项目中添加数据库过程中出现了小问题,就是使用sql server身份验证没登录成功,经过一番调试,终于解决问题. 使用sa账户登录sql server 2008 的方法步骤如下: 1.首先 ...

  8. WeTest+微信:小程序云端测试系统上线

    日前,微信新增小程序测试系统,可便于开发者检测小程序缺陷,评估小程序产品质量.在小程序发布之前,开发者可将小程序代码提交到测试系统,在不同型号的手机真机上运行,执行完毕后自动生成测试报告.小程序云端测 ...

  9. MySQL (三)-- 字段属性、索引、关系、范式、逆规范化

    1 字段属性 主键.唯一键和自增长. 1.1 主键 主键:primary key,一张表中只能有一个字段可以使用对应的键,用来唯一的约束该字段里面的数据,不能重复. 一张表只能有最多一个主键. 1.1 ...

  10. 软件工程HW1-四则运算软件

    题目描述 程序自动生成小学四则运算题目,用户输入每道题的答案之后,将答错的题目标出并计算此次答题的正确率. 项目链接 我的项目 项目运行截图 个人软件过程 此次开发的四个步骤: 1):需求分析 2): ...