举个简单的例子:

public class Hello {
    public static void main(String[] args) {
        String string1 = "ab";
        String string2 = "c";
        String string3 = string1 + "c";
        System.out.println(string1 == string3);
    }
}

过程大致分析如图:

第一步 将线程栈中的string1、string2引用分别指向了常量池ab、c的地址。

第二步 轮到了string3 = string1 + "c",首先会初始化StringBuilder到堆中,然后调append将string1字符串拼接、然后调append再拼接"c"。

第三步 StringBuilder指向常量池的"abc"地址,然后通过toString返回值.

然后执行如下指令:

$ javac Hello.java   //编译

$ javap -verbose Hello   //反编译,结果如下:
Classfile /C:/Users/lisam/Desktop/新建文件夹/Hello.class

  Last modified 2018-9-17; size 706 bytes

  MD5 checksum 4d2164bd48f0690cad84271e27b237a5

  Compiled from "Hello.java"

public class Hello

  SourceFile: "Hello.java"

  minor version: 0

  major version: 51

  flags: ACC_PUBLIC, ACC_SUPER

//方法常量池

Constant pool:

   #1 = Methodref          #11.#24        //  java/lang/Object."<init>":()V

   #2 = String             #25            //  ab

   #3 = String             #26            //  c

   #4 = Class              #27            //  java/lang/StringBuilder

   #5 = Methodref          #4.#24         //  java/lang/StringBuilder."<init>":()V

   #6 = Methodref          #4.#28         //  java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

   #7 = Methodref          #4.#29         //  java/lang/StringBuilder.toString:()Ljava/lang/String;

   #8 = Fieldref           #30.#31        //  java/lang/System.out:Ljava/io/PrintStream;

   #9 = Methodref          #32.#33        //  java/io/PrintStream.println:(Z)V

  #10 = Class              #34            //  Hello

  #11 = Class              #35            //  java/lang/Object

  #12 = Utf8               <init>

  #13 = Utf8               ()V

  #14 = Utf8               Code

  #15 = Utf8               LineNumberTable

  #16 = Utf8               main

  #17 = Utf8               ([Ljava/lang/String;)V

  #18 = Utf8               StackMapTable

  #19 = Class              #36            //  "[Ljava/lang/String;"

  #20 = Class              #37            //  java/lang/String

  #21 = Class              #38            //  java/io/PrintStream

  #22 = Utf8               SourceFile

  #23 = Utf8               Hello.java

  #24 = NameAndType        #12:#13        //  "<init>":()V

  #25 = Utf8               ab

  #26 = Utf8               c

  #27 = Utf8               java/lang/StringBuilder

  #28 = NameAndType        #39:#40        //  append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

  #29 = NameAndType        #41:#42        //  toString:()Ljava/lang/String;

  #30 = Class              #43            //  java/lang/System

  #31 = NameAndType        #44:#45        //  out:Ljava/io/PrintStream;

  #32 = Class              #38            //  java/io/PrintStream

  #33 = NameAndType        #46:#47        //  println:(Z)V

  #34 = Utf8               Hello

  #35 = Utf8               java/lang/Object

  #36 = Utf8               [Ljava/lang/String;

  #37 = Utf8               java/lang/String

  #38 = Utf8               java/io/PrintStream

  #39 = Utf8               append

  #40 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;

  #41 = Utf8               toString

  #42 = Utf8               ()Ljava/lang/String;

  #43 = Utf8               java/lang/System

  #44 = Utf8               out

  #45 = Utf8               Ljava/io/PrintStream;

  #46 = Utf8               println

  #47 = Utf8               (Z)V

{

  public Hello();

    flags: ACC_PUBLIC

    Code:

      stack=1, locals=1, args_size=1

         0: aload_0       

         1: invokespecial #1                  // Method java/lang/Object."<init>":()V

         4: return        

      LineNumberTable:

        line 1: 0

  public static void main(java.lang.String[]);

    flags: ACC_PUBLIC, ACC_STATIC

    Code:

      stack=3, locals=4, args_size=1

         //将字符串"ab"压入常量池

         0: ldc           #2                  // String ab

         //存储到局部变量表

         2: astore_1      

         //将字符串"c"压入常量池

         3: ldc           #3                  // String c

         //存储到局部变量表

         5: astore_2      

         //String3的拼接过程中,会先new

         6: new           #4                  // class java/lang/StringBuilder

         9: dup           

         //然后invokespecial调用初始化StringBuilder构造器

        10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V

        //把局部变量表中n=1的引用(即步骤2: astore_1)的值"ab"装在到操作数栈中。

        13: aload_1       

        //然后invokevirtual来调用方法append  string1

        14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

        //将字符串"c"压入常量池

        17: ldc           #3                  // String c

        //然后append "c"

        19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

        //调用toString返回值

        22: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

        //然后将string3的值"abc"存储到局部变量表

        25: astore_3      

        //获取类的静态域,这里拿到了静态System.out,并将值压入栈顶

        26: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;

        //把局部变量表中n=1的引用(即步骤2: astore_1)的值"ab"装在到操作数栈中。

        29: aload_1      

        //把局部变量表中n=3的引用(即步骤25: astore_3)的值"abc"装在到操作数栈中。

        30: aload_3       

        //比较上面栈顶两引用型数值,当结果不相等时跳转

        31: if_acmpne     38

        //将int为1压入栈顶

        34: iconst_1      

        35: goto          39

        38: iconst_0      

        //调用静态类中System.out.println

        39: invokevirtual #9                  // Method java/io/PrintStream.println:(Z)V

        //返回空

        42: return        

      LineNumberTable:

        line 3: 0

        line 4: 3

        line 5: 6

        line 6: 26

        line 7: 42

      StackMapTable: number_of_entries = 2

           frame_type = 255 /* full_frame */

          offset_delta = 38

          locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String ]

          stack = [ class java/io/PrintStream ]

           frame_type = 255 /* full_frame */

          offset_delta = 0

          locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String ]

          stack = [ class java/io/PrintStream, int ]

}
 

原文链接:Java字节码例子解析 - Lisam Blog - CSDN博客  https://blog.csdn.net/qq_28666081/article/details/82749655

参考链接:一文让你明白Java字节码 - 简书  https://www.jianshu.com/p/252f381a6bc4

Java字节码例子解析的更多相关文章

  1. OpenJDK源码研究笔记(八)-详细解析如何读取Java字节码文件(.class)

    在上一篇OpenJDK源码研究笔记(七)–Java字节码文件(.class)的结构中,我们大致了解了Java字节码文件的结构. 本篇详细地介绍了如何读取.class文件的大部分细节. 1.构造文件  ...

  2. 【JVM源码解析】模板解释器解释执行Java字节码指令(上)

    本文由HeapDump性能社区首席讲师鸠摩(马智)授权整理发布 第17章-x86-64寄存器 不同的CPU都能够解释的机器语言的体系称为指令集架构(ISA,Instruction Set Archit ...

  3. JAVA字节码解析

    Java字节码指令 Java 字节码指令及javap 使用说明 ### java字节码指令列表 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送 ...

  4. 从 HelloWorld 看 Java 字节码文件结构

    很多时候,我们都是从代码层面去学习如何编程,却很少去看看一个个 Java 代码背后到底是什么.今天就让我们从一个最简单的 Hello World 开始看一看 Java 的类文件结构. 在开始之前,我们 ...

  5. Java字节码里的invoke操作&&编译时的静态绑定与动态绑定

    一个一直运行正常的应用突然无法运行了.在类库被更新之后,返回下面的错误. Exception in thread "main" java.lang.NoSuchMethodErro ...

  6. JVM 内部原理(六)— Java 字节码基础之一

    JVM 内部原理(六)- Java 字节码基础之一 介绍 版本:Java SE 7 为什么需要了解 Java 字节码? 无论你是一名 Java 开发者.架构师.CxO 还是智能手机的普通用户,Java ...

  7. 轻松看懂Java字节码

    java字节码 计算机只认识0和1.这意味着任何语言编写的程序最终都需要经过编译器编译成机器码才能被计算机执行.所以,我们所编写的程序在不同的平台上运行前都要经过重新编译才能被执行. 而Java刚诞生 ...

  8. 大话+图说:Java字节码指令——只为让你懂

    前言 随着Java开发技术不断被推到新的高度,对于Java程序员来讲越来越需要具备对更深入的基础性技术的理解,比如Java字节码指令.不然,可能很难深入理解一些时下的新框架.新技术,盲目一味追新也会越 ...

  9. 硬核万字长文,深入理解 Java 字节码指令(建议收藏)

    Java 字节码指令是 JVM 体系中非常难啃的一块硬骨头,我估计有些读者会有这样的疑惑,"Java 字节码难学吗?我能不能学会啊?" 讲良心话,不是我谦虚,一开始学 Java 字 ...

随机推荐

  1. ACM-ICPC 2017北京

    J. Pangu and Stones 大意: 给定$n$堆石子, $(n\le 100)$, 每次操作任选连续的至少$L$堆至多$R$堆合并, 代价为合并石子的总数, 求合并为$1$堆的最少花费. ...

  2. 怎样创建一个canvas画布环境

    1. 由于canvas画布在网页中, 所以需要在html中添加canvas标签: <!DOCTYPE html> <html lang="en"> < ...

  3. Image 对象事件

    以前没怎么注意image上的事件 Image 对象事件 事件 描述 W3C onabort 当用户放弃图像的装载时调用的事件句柄. Yes onerror 在装载图像的过程中发生错误时调用的事件句柄. ...

  4. LeetCode 腾讯精选50题--二叉树中的最大路径和

    二叉树中的最大路径和 题目描述 给定一个非空二叉树,返回器最大路径和,路径指一条从任意节点出发,到达任意节点的序列,该路径至少包含一个节点,且不一定经过根节点 解题思路 树这一类数据结构我还不是很熟悉 ...

  5. 2.IOC 配置与应用(xml的方式)

    1.注入方式 a)setter(主要) b)构造方法(可以忘记) c)接口注入(可以忘记) 2.id  vs  name bean 标签中可以使用  name 属性 来完成 id 属性的功能,不过习惯 ...

  6. ASE19团队项目alpha阶段model组 scrum8 记录

    本次会议于11月12日,19时整在微软北京西二号楼sky garden召开,持续15分钟. 与会人员:Jiyan He, Kun Yan, Lei Chai, Linfeng Qi, Xueqing ...

  7. JAVA 内存模型(主内存,工作内存)

    JVM将内存组织为主内存和工作内存两个部分. 主内存是所有的线程所共享的,主要包括本地方法区和堆. 每个线程都有一个工作内存不是共享的,工作内存中主要包括两个部分: 1:一个是属于该线程私有的栈; 2 ...

  8. Linux文件的管理

    创建:touch  vim/vi  echo重定向  cat touch 管理: atime  mtime touch  文件名  //如果文件不存在,不创建文件 删除:mv /tmp find |x ...

  9. Vsftpd Nginx

    Linux(CentOS-6.10)下安装Vsftpd Nginx 1:创建FTP专属的账户和密码[root@localhost ~]# useradd ftpuser[root@localhost ...

  10. 底部版权时间自动变化,网页在线qq咨询

    <p><small>© 众筹网<script>document.write(new Date().getFullYear());</script> &l ...