本文故事构思来源于脉脉上的一篇帖子“一行代码引发的血案”。

其实关于字符串的文章,我之前也写过一篇《诡异的字符串问题》,字符串对于我们开发者而言,可以用最近很流行的一句话“用起来好嗨哟,仿佛人生达到了巅峰”。

确实大家都用的很嗨,很便利,但 JDK 的工程师在背后付出了努力又有几个人真的在意呢?

咱们今天就通过一个例子来详细的说明。

public class StringTest {public static void main(String[] args) {// 无变量的字符串拼接String s = "aa"+"bb"+"dd";System.out.println(s);// 有变量的字符串拼接String g = "11"+s+5;System.out.println(g);// 循环中使用字符串拼接String a = "0";for (int i = 1; i < 10; i++) {a = a + i;}System.out.println(a);// 循环外定义StringBuilderStringBuilder b = new StringBuilder();for (int i = 1; i < 10; i++) {b.append(i);}System.out.println(b);}
}
复制代码

有同学可能会说,这么一段代码,怎么来区分呢?既然我在对话中说了 Java 从 JDK5 开始,便在编译期间进行了优化,那么编译期间 javac 命令主要干了什么事情呢?一句话归根结底,那么肯定就是把 .java 源码编译成 .class 文件,也就是我们常说的中间语言——字节码。然后 JVM 引擎再对 .class 文件进行验证,解析,翻译成本地可执行的机器指令,这只是一个最简单的模型,其实现在的 JVM 引擎后期还会做很多优化,比如代码热点分析,JIT编译,逃逸分析等。

说到这里,我记得之前群里有同学说,字节码长得太丑了,看了第一眼就不想看第二眼,哈哈,丑是丑点,但是很有内涵,能量强大,实现了跨平台性。

关于怎么查看字节码,我之前分享过两个工具,一个 JDK 自带的 javap,另一个IDEA的插件 jclasslib Bytecode viewer。今天给你再分享一个,我之前破解 apk 常用的工具 jad,它会让你看字节码文件轻松很多。

先说一下,我分别用 Jdk 1.6 - 1.8 自带的 javap 工具进行了反编译,发现生成的 JVM 指令是一样的,所以在此处不会列出每一个版本生成的指令文件。为了便于大家阅读指令文件,这里用jad工具生成,代码如下。

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) annotate
// Source File Name:   StringTest.javaimport java.io.PrintStream;public class StringTest
{public StringTest(){//    0    0:aload_0         //    1    1:invokespecial   #1   <Method void Object()>//    2    4:return          }public static void main(String args[]){String s = "aabbdd";//    0    0:ldc1            #2   <String "aabbdd">//    1    2:astore_1        System.out.println(s);//    2    3:getstatic       #3   <Field PrintStream System.out>//    3    6:aload_1         //    4    7:invokevirtual   #4   <Method void PrintStream.println(String)>String g = (new StringBuilder()).append("11").append(s).append(5).toString();//    5   10:new             #5   <Class StringBuilder>//    6   13:dup             //    7   14:invokespecial   #6   <Method void StringBuilder()>//    8   17:ldc1            #7   <String "11">//    9   19:invokevirtual   #8   <Method StringBuilder StringBuilder.append(String)>//   10   22:aload_1         //   11   23:invokevirtual   #8   <Method StringBuilder StringBuilder.append(String)>//   12   26:iconst_5        //   13   27:invokevirtual   #9   <Method StringBuilder StringBuilder.append(int)>//   14   30:invokevirtual   #10  <Method String StringBuilder.toString()>//   15   33:astore_2        System.out.println(g);//   16   34:getstatic       #3   <Field PrintStream System.out>//   17   37:aload_2         //   18   38:invokevirtual   #4   <Method void PrintStream.println(String)>String a = "0";//   19   41:ldc1            #11  <String "0">//   20   43:astore_3        for(int i = 1; i < 10; i++)//*  21   44:iconst_1        //*  22   45:istore          4//*  23   47:iload           4//*  24   49:bipush          10//*  25   51:icmpge          80a = (new StringBuilder()).append(a).append(i).toString();//   26   54:new             #5   <Class StringBuilder>//   27   57:dup             //   28   58:invokespecial   #6   <Method void StringBuilder()>//   29   61:aload_3         //   30   62:invokevirtual   #8   <Method StringBuilder StringBuilder.append(String)>//   31   65:iload           4//   32   67:invokevirtual   #9   <Method StringBuilder StringBuilder.append(int)>//   33   70:invokevirtual   #10  <Method String StringBuilder.toString()>//   34   73:astore_3        //   35   74:iinc            4  1//*  36   77:goto            47System.out.println(a);//   37   80:getstatic       #3   <Field PrintStream System.out>//   38   83:aload_3         //   39   84:invokevirtual   #4   <Method void PrintStream.println(String)>StringBuilder b = new StringBuilder();//   40   87:new             #5   <Class StringBuilder>//   41   90:dup             //   42   91:invokespecial   #6   <Method void StringBuilder()>//   43   94:astore          4for(int i = 1; i < 10; i++)//*  44   96:iconst_1        //*  45   97:istore          5//*  46   99:iload           5//*  47  101:bipush          10//*  48  103:icmpge          120b.append(i);//   49  106:aload           4//   50  108:iload           5//   51  110:invokevirtual   #9   <Method StringBuilder StringBuilder.append(int)>//   52  113:pop             //   53  114:iinc            5  1//*  54  117:goto            99System.out.println(b);//   55  120:getstatic       #3   <Field PrintStream System.out>//   56  123:aload           4//   57  125:invokevirtual   #12  <Method void PrintStream.println(Object)>//   58  128:return          }
}
复制代码

这里说一下分析结果。

1、无变量的字符串拼接,在编译期间值都确定了,所以 javac 工具帮我们把它直接编译成一个字符常量。

2、有变量的字符串拼接,在编译期间变量的值无法确定,所以运行期间会生成一个StringBuilder 对象。

3、循环中使用字符串拼接,循环内,每循环一次就会产生一个新的 StringBuilder 对象,对资源有一定的损耗。

4、循环外使用 StringBuilder,循环内再执行 append() 方法拼接字符串,只会成一个 StringBuilder 对象。

因此,对于有循环的字符串拼接操作,建议使用 StringBuilder 和 StringBuffer,对性能会有一定的提升。

其实上面的结论,《阿里巴巴Java开发手册》中有所提到,此文正好与该条结论相对应。

一个简单的字符串,用起来确实简单,背后付出了多少工程师的心血,在此,深深地佩服詹爷。

PS:本文原创发布于微信公众号 「Java面试那些事儿」,关注并回复「1024」,免费领学习资料。 原文地址

转载于:https://juejin.im/post/5c400d44f265da614f708e68

漫画:老板扣了我1000,因为我没记住阿里巴巴开发手册的这条规则。相关推荐

  1. 老板扣了我1000,因为我没记住阿里巴巴开发手册的这条规则。

    来源:Java面试那些事儿 本文故事构思来源于脉脉上的一篇帖子"一行代码引发的血案". 其实关于字符串的文章,我之前也写过一篇<诡异的字符串问题>,字符串对于我们开发者 ...

  2. 漫画丨让你专心干技术,没让你干到35岁啊…

    漫画丨让你专心干技术,没让你干到35岁啊- https://www.toutiao.com/i6934625131939774983/?tt_from=weixin&utm_campaign= ...

  3. 老版本微信平台服务器部署步骤(没那么坑版)

    老版本微信平台服务器部署步骤(没那么坑版) By Levy 1.  用putty登陆服务器 2.  安装需要的程序(nginx/python/pip/virtualenv) 3.  使用virtual ...

  4. 该终端已停用_宣杭老线停用,勾庄、三墩、仓前、老余杭、瓶窑三千多亩地待开发...

    一 周 速 递 1.时隔120多天,主城区土拍1月5日重启 2.杭州地铁7号线首通段开通倒计时 3.杭州地铁6号线预计年底通车 4.宣杭老线今日正式停用 5.崇贤-老余杭连接线高架桥预计明年竣工 6. ...

  5. 都说DBA 是越老越值钱, 那你是没干过DBA

    正式干DBA 也是有些年头了,十几年是有了, 前些日子翻出最早买的一本数据库的书是2001年的.这么多年,身边的开发,项目经理,应用运维等等这些"友人", 说的最多的一句话就是, ...

  6. 漫画 | 产品经理频繁更改需求,我没忍住把他给砍了!

    众所周知,程序员是一类思维比较特殊的群体,但他们也有不为人知的烦恼,最常见的是经常被产品经理频繁改需求.拿老板来压人等-,而这些烦恼外行人是很难理解的. 就像前些年就出现过"软件公司老板被员 ...

  7. 龙书啃不动?老司机带你从零入门编译原理,开发编译器

    计算机只认识二进制的,但是我们平常开发中根本不会使用二进制进行开发,我们使用的都是 Java.C.Python 这类的高级语言.每种语言都会经过一系列的转换才能被计算机识别,那么到底是谁做的这项工作呢 ...

  8. mysql环境搭载后老出错_使用Docker在window10下搭建SWOFT开发环境,mysql连接错误

    使用Docker在window10下搭建SWOFT开发环境,mysql连接错误 { "code": 0, "error": "(Swoft\\Db\\ ...

  9. ntnub原理怎么看_老电工由浅入深带你入门学PLC的工作原理和梯形图的编程规则...

    PLC编程怎么学?很难吗?工控小白怎么入门学习PLC?需要为学习PLC编程做哪些准备?学习PLC编程时,前期一定要积累相关的理论知识,有了一定的基础,基础打扎实之后就是多练习了.今天推荐的重点,是关于 ...

最新文章

  1. 看我如何作死 | 将CPU、IO打爆
  2. Learun对快速开发平台的基本认知与设定
  3. 设置同一Label内涵不同颜色字体
  4. 产品经理跳槽面试大揭秘……
  5. 笔记-高项案例题-2019年下-计算题
  6. C语言再学习 -- C 预处理器
  7. 百度AI学习:三、文字识别
  8. 数据库零碎---mysql编码设置,与乱码分析
  9. 3.3 rsync同步之ssh隧道方式
  10. display: flex; 的兼容问题解决办法
  11. 探讨绝对哲学存在的必要条件
  12. 基于OpenCV文字特征提取
  13. sql如何在两张表中得到每组数据,并知道数据的个数,举例,判断有多少班级,每个班的人数
  14. 1067 Sort with Swap(0, i) (25 分) 好,容易出错
  15. java中queue与stroke,ae中stroke的用法
  16. Verilog 语法合集
  17. 健身用肌酸市场前景分析及行业研究报告
  18. Python实现股票查询
  19. 剑指 Offer 19. 正则表达式匹配 regex_match() regex()
  20. word2007 正文自动变为大纲一级 问题

热门文章

  1. python读取mysql数据_如何将mysql的数据读取python
  2. linux共享文件权限设置,linux – Windows更改Samba文件共享中的文件权限
  3. 计算机二级语义网络的研究现状与展望,计算机二级access选择题题库研究.doc
  4. 河北师范大学计算机专业保研率,河北省内13所高校2021届保研率一览
  5. python注册用户名和密码登录_python实现自动登录需要用户名和密码的网站
  6. python初级语法_python语法基础
  7. vision画流程图的软件_产品流程图的定义,作用和画法
  8. centos7.2 安装mysql5.6_Centos7安装mysql5.6
  9. html5基础知识点表单
  10. 1.2 函数间隔和几何间隔理解2