举个简单的例子:

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. 怎样安装并编译TypeScript?

    1. 使用: npm -v 查看是否安装了 npm ,  如果没有安装, 请前往 Nodejs 官网 下载安装, 下图表示已经安装 npm , 版本为: 6.9.0 . PS C:\Users\Adm ...

  2. HTTP协议探究(三):HTTPS

    一 复习与目标 1 复习 代理:转发通信数据(一般协议不变,作为中间人,可对报文进行过滤修改) 网关:转发通信数据(协议改变,作为资源拥有者) 隧道:转发通信数据(协议不变,作为管道,不对报文进行过滤 ...

  3. 史上最全Java集合中List,Set以及Map等集合体系详解

    一.概述 List , Set, Map都是接口,前两个继承至collection接口,Map为独立接口 Set下有HashSet,LinkedHashSet,TreeSet List下有ArrayL ...

  4. Zircon

    Zircon 来源 https://github.com/zhangpf/fuchsia-docs-zh-CN/tree/master/docs/the-book 国内镜像源 https://hexa ...

  5. 使用Seaborn展示多变量两两之间的关系

    数据展示: 1. FacetGrid FacetGrid是一个储存我们想怎样展示信息的东西,如下所示,我们想观察位置中SK和GK的分布. 在这里我们使用map方法把数据填充到图表中 计算类别在某一特征 ...

  6. ES5中一些重要的拓展

    1.对象的拓展 ①Object.create(obj, {age:{value:18, writable:true, configurable:true, enumerable:true}); 以指定 ...

  7. HashMap闭环(死循环)的详细原因(转)

    为何出现死循环简要说明 HashMap是非线程安全的,在并发场景中如果不保持足够的同步,就有可能在执行HashMap.get时进入死循环,将CPU的消耗到100%. HashMap采用链表解决Hash ...

  8. 5.AOP配置与应用(annotation的方式)

    步骤: a)在beans.xml文件中加上对应的xsd文件 spring-aop.xsd b)加上<aop:aspectj-autoproxy>,使用aspectj来完成aop <! ...

  9. Man手册--nmap

    目录 nmap使用手册 附录: nmap使用手册 附录: NMAP(1) Nmap Reference Guide NMAP(1) NAME nmap - Network exploration to ...

  10. Oracle笔记(十二) 集合、序列

    一.集合 在数学的操作之中存在交.差.并.补的概念,而在数据的查询中也存在此概念,有如下几个连接符号: UNION:连接两个查询,相同的部分不显示: UNION ALL:连接两个查询,相同的部分显示: ...