来源:Java面试那些事儿

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

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

确实大家都用的很嗨,很便利,但 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);        // 循环外定义StringBuilder        StringBuilder 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.java

import 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          80            a = (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            47        System.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          4        for(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          120            b.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            99        System.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开发手册》中有所提到,此文正好与该条结论相对应。

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

号外:最近整理了一下以前编写的一系列Spring Boot内容,整了个《Spring Boot基础教程》的PDF,关注我,回复:001,快来领取吧~!002 资源也即将整理出炉,先关注我吧!随后奉上更多精选学习资料!!!

·END·

 近期热文:

  • SpringCloudAlibaba基础教程:使用Nacos实现服务注册与发现

  • “三次握手,四次挥手”你真的懂吗?

  • “拼多多”被薅的问题出在哪儿?损失将如何买单?

  • 在前后端分离的路上承受了多少痛?看看这篇是否能帮到你?

  • 你真的会高效的在GitHub上搜索开源项目吗?

  • Spring Boot:自定义starter

  • 中台是个什么鬼?

  • 从业务到平台的思维转变

  • 是什么使你留在你的公司

  • 重磅!Github 开放无数量限制的免费私有仓库!

  • 百度面试题:求数组最大值

看完,赶紧点个“好看”鸭

点鸭点鸭

↓↓↓↓

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

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

    本文故事构思来源于脉脉上的一篇帖子"一行代码引发的血案". 其实关于字符串的文章,我之前也写过一篇<诡异的字符串问题>,字符串对于我们开发者而言,可以用最近很流行的一句 ...

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

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

  3. 苦逼的是怎么又有东西没记住,但我们依然每天坚持一遍、一遍又一遍指导记住为止。

    期待的是可以检验自己学习的成功:苦逼的是怎么又有东西没记住,但我们依然每天坚持一遍.一遍又一遍指导记住为止. 原本以为大家会把讲过的都记录下来,以便日后毕业复习,事实证明18岁的我还是太年轻. 一切想 ...

  4. 都1202年了,阿里五岳版的《Java开发手册》你还没拜读过?

    都2021年了相信有很多人已经看过阿里五岳版的<Java开发手册>了! 没看过也没有关系,因为我今天给大家分享出来这份阿里开发手册五岳版的核心总结篇! 如果想获取开发手册的话可以直接添加助 ...

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

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

  6. 做自媒体值实用的九个网站,身为老司机的你你用过没?

    嗨咯,大家好,这里依旧为自媒体人推送你所想了解的平台运营方法技巧,在前面我们已经讲到了百家号的注册以及运营的小技巧,在这里给大家分享几个好用又实用的网站,希望对你们有帮助哦~ 作为一个自媒体人,内容素 ...

  7. 油腻老爷们,你是有多久没化过妆了?

    因为有些需求[原因在文末],需要拍一张正装照. 我已经受够了那些小摄像馆拍的照片了, 完全拍不出我的神韵! 效果还不如我手机开个美颜! 生活问题,有时候问邻居效率很高! 在小区群里,问了一下邻居! 立 ...

  8. ​阿里巴巴总市值超过4000亿美元,“股神”巴菲特:没买阿里巴巴股票是个错误!...

      7月27日晚间,美股上市的阿里巴巴(NYSE:BABA)总市值突破4000亿美元,截至发稿股价上涨1.81%,报于每股158.92美元,总市值达到4070亿美元. 在最近的一档访谈节目中,现年87 ...

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

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

最新文章

  1. meson 中调用shell script
  2. IOS入门-TargetAction
  3. 吴恩达 coursera AI 专项四第三课总结+作业答案
  4. Git出现Unable to create 'E:/xxx/.git/index.lock': File exists.的解决办法
  5. 招行率先落地房贷新政 其他银行细则仍在制定
  6. 大数据安全分析有哪些常见问题
  7. 黑链-最高明的网站隐藏链接方法
  8. lumion制作海上明月5.29
  9. php项目过段时间就崩溃,apache 运行一段时间出现错误
  10. mysql 插入多条值_mysql一次性插入多条数据
  11. Python编程快速上手-让繁琐工作自动化 — 读书与代码笔记
  12. 2021年全球高级相变材料(PCM)收入大约1513.7百万美元,预计2028年达到3220.4百万美元
  13. 课程设计实验--火车票座位分配
  14. vue3中组件给后代组件传值,provide和inject的使用
  15. 位图(BMP)文件格式(一)
  16. 少儿编程和机器人编程哪个更好一点
  17. 华为区块链白皮书(一)
  18. 【逐梦旅程Windows游戏编程学习笔记 ①】基本GDI绘图
  19. 几天时间【免费】搭建了自己的个人博客,免租服务器,免买域名,真香警告。
  20. 搜索与图论1—深搜、宽搜、拓扑排序

热门文章

  1. linux 软件安装 NOKEY问题
  2. linux shell脚本 静态检查工具 shellcheck 简介
  3. python3 得到一个可用未绑定端口
  4. linux 反弹shell(二)反弹shell的本质
  5. tcp socket 异常关闭总结
  6. VS2010 运行速度加快方法
  7. Android开发精要1--Android系统架构
  8. JAVA String.format 方法使用介绍
  9. Linux系统的启动引导过程
  10. oracle导入dmp方法,oracle dmp文件导入方法