举个简单的例子:

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. Java门面模式(思维导图)

    图1 门面模式[点击查看图片] 1,实体对象类 package com.cnblogs.mufasa.demo1; //3个子系统,解决问题的实体 public class StoreA { //示意 ...

  2. c#学习笔记-string stringBuilder

    string aTest = "abc";//分配固定的内存大小 aTest += "ddd"; //销毁原先的数据再来分配,消耗大 StringBuilder ...

  3. Java通过JDBC连接SQL Server

    下载Microsoft JDBC Driver 4.0 for SQL Server 在这里下载:http://www.microsoft.com/zh-cn/download/details.asp ...

  4. Javascript绑定事件的两种方式的区别

    命名函数 <input type="button" onclick="check()" id="btn"/> <scrip ...

  5. Nginx笔记一

      nginx: 为什么选择nginx: nginx是一个高性能的web和反向代理服务器. 作为web服务器:使用更少的资源,支持更多的并发连接,更高的效率,能够支持高达5w个并发连接数的相应, 作为 ...

  6. 简要了解web安全之sql注入

    什么是sql注入? 通俗来讲就是通过 将可执行sql语句作为参数 传入查询sql 中,在sql编译过程中 执行了传入进来的恶意 sql,从而 得到 不应该查到或者不应该执行的sql语句,对网站安全,信 ...

  7. 6.B+Tree 检索原理

    B+树的创建(索引的创建) 1.比如为phoneNum创建了一个索引,phoneNum这列保存了很多的手机号码 2.索引创建的过程中,会为这些数据进行适当的编码(根据这个数据所在的物理地址),如 36 ...

  8. sql循环-游标、临时表、表变量

    游标 在游标逐行处理过程中,当需要处理的记录数较大,而且游标处理位于数据库事务内时,速度非常慢. -- 声明变量 DECLARE @Id AS Int -- 声明游标 DECLARE C_Id CUR ...

  9. ARMA(p,q)模型数据的产生

    一.功能 产生自回归滑动平均模型\(ARMA(p,q)\)的数据. 二.方法简介 自回归滑动平均模型\(ARMA(p,q)\)为 \[ x(n)+\sum_{i=1}^{p}a_{i}x(n-i)=\ ...

  10. 聚类算法之MeanShift

    机器学习的研究方向主要分为三大类:聚类,分类与回归. MeanShift作为聚类方法之一,在视觉领域有着广泛的应用,尤其是作为深度学习回归后的后处理模块而存在着. 接下来,我们先介绍下基本功能流程,然 ...