举个简单的例子:

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. NopCommerce的autofac的理解

    nop项目4.1是core.2.1开发的,Startup.cs文件开始 从入口进去ServiceCollectionExtensions这个文件 this IServiceCollection ser ...

  2. Ubuntu16.04 + caffe + cuda 环境搭建

    1. sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-de ...

  3. js之数据类型(对象类型——构造器对象——正则)

    正则(regular expression)描述了一种字符串的匹配式.一般应用在一些方法中,用一些特殊的符号去代表一些特定的内容,对字符串中的信息实现查找,替换,和提取的操作.js中的正则表达式用Re ...

  4. SQL学习——LIKE运算符

    原文链接 LIKE 作用 在WHERE子句中使用LIKE运算符来搜索列中的指定模式. 有两个通配符与LIKE运算符一起使用: % - 百分号表示零个,一个或多个字符 _ - 下划线表示单个字符 注意: ...

  5. Lab2 Report

    1.安装SeleniumIDE插件 a)安装Firefox 17.0 - 56.*版本的firefox,下载地址为:http://ftp.mozilla.org/pub/firefox/release ...

  6. 5.Servlet 对象(request-response)

    /*ServletResponse*/ /*responese常见应用*/ 1.向客户端输出中文数据 (分别以OutputStream 和 PrintWriter输出) 2.文件下载和中文文件的下载 ...

  7. WPF实战案例-在线程内同步集合数据到UI线程

    有这样一个场景,在vm中,我们为了ui的体验,会异步访问后端接口,获取数据集合,如果这个集合绑定到界面,并且在线程内,怎么处理? 有人讲:this.Dispatcher.Invoke,如果在vm内呢? ...

  8. Python3 GUI:PyQt5环境搭建

    配置镜像源 最近用Python内置的Thinter写了个小工具,发现界面略朴素,于是决定转向PyQt5.先配置镜像源,否则只能龟速下载. C:\Users\你的用户名下新建目录pip 在pip目录下新 ...

  9. es string 分词完整示例

    "products_name_en": {            "type":  "string", //字符串类型            ...

  10. Sql 语法练习

    select * from Student select * from Class select * from Score select * from Subject --1.查询出和张三住在同一个地 ...