Java字节码

Java字节码是Java源代码经过编译器编译生成的二进制格式,它是一种面向栈的指令集架构。Java字节码由一系列指令组成,用于执行各种操作,如加载和存储数据、进行算术和逻辑运算、控制流程等。

字节码是由Java虚拟机(JVM)解释和执行的。JVM将字节码加载到内存中,并根据指令逐条执行。这种中间语言的设计使得Java可以实现平台无关性,因为不同的操作系统和硬件只需提供对应的JVM实现即可执行Java字节码。

Java源码

public class SynchronizedDemo {
    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        synchronized (synchronizedDemo) {
            System.out.println("synchronized demo ...");
        }
    }

}

编译后的class文件

package com.fei.multiThread.threadPool;

public class SynchronizedDemo {
    public SynchronizedDemo() {
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        synchronized(synchronizedDemo) {
            System.out.println("synchronized demo ...");
        }
    }
}

查看字节码,在IDEA中点击编译后的class,View ---> Show Bytecode

// class version 52.0 (52)
// access flags 0x21   表示该类、字段或方法具有公共访问级别,并且在调用父类方法时使用特殊调用指令。
public class com/fei/multiThread/threadPool/SynchronizedDemo {

  // compiled from: SynchronizedDemo.java

  // access flags 0x1  表示该类、字段或方法具有公共访问级别。
  public <init>()V  表示一个公共的构造方法,没有参数,并且没有返回值。
   L0  L0​ 是一个标签,用于标识字节码中的一个位置。在这段字节码中,​L0​ 标签出现在构造方法 ​<init>()V​ 的开始处。
    LINENUMBER 8 L0  表示源代码的行号为 8,对应于 ​L0​ 标签所在的位置。
    ALOAD 0  将当前对象引用加载到操作数栈上。
    INVOKESPECIAL java/lang/Object.<init> ()V  调用了父类 ​java/lang/Object​ 的构造方法,以初始化对象。
    RETURN  表示从构造方法中返回。
   L1  在这段字节码中,​L1​ 标签出现在构造方法 ​<init>()V​ 的结束处。
    LOCALVARIABLE this Lcom/fei/multiThread/threadPool/SynchronizedDemo; L0 L1 0  表示在方法范围内定义了一个局部变量 ​this​,它的类型是 ​Lcom/fei/multiThread/threadPool/SynchronizedDemo;​(即当前类的类型),在代码范围从 ​L0​ 到 ​L1​ 处有效,且该局部变量的槽位索引为 0。
    MAXSTACK = 1  表示在方法执行时,操作数栈的最大深度为 1。
    MAXLOCALS = 1 表示在方法执行时,局部变量表的最大槽位索引为 1。

  // access flags 0x9  表示该字段或方法具有公共访问级别,是静态的,并且是不可变的。
  public static main([Ljava/lang/String;)V  表示一个公共的静态方法 ​main​,该方法接受一个 ​String​ 数组作为参数,并且没有返回值。
    // parameter  args  表示方法的参数名为 ​args​,它是一个 ​String​ 数组。
    TRYCATCHBLOCK L0 L1 L2 null  表示在 ​L0​ 到 ​L1​ 的代码范围内可能会抛出异常,并且在发生异常时,将跳转到 ​L2​ 处进行异常处理。 ​​null​:表示异常类型为任意异常。
    TRYCATCHBLOCK L2 L3 L2 null   表示在 ​L2​ 到 ​L3​ 的代码范围内可能会抛出异常,并且在发生异常时,将跳转到 ​L2​ 处进行异常处理。
   L4  ​L4​ 标签出现在 ​main​ 方法中的一系列指令的开始处。
    LINENUMBER 10 L4  表示源代码的行号为 10,对应于 ​L4​ 标签所在的位置。
    NEW com/fei/multiThread/threadPool/SynchronizedDemo  创建了一个新的 ​com/fei/multiThread/threadPool/SynchronizedDemo​ 类型的对象。
    DUP  复制了对象引用,将其放入操作数栈的顶部。
    INVOKESPECIAL com/fei/multiThread/threadPool/SynchronizedDemo.<init> ()V  调用了 ​com/fei/multiThread/threadPool/SynchronizedDemo​ 类的构造方法 ​<init>()​,用于初始化对象。
    ASTORE 1  将操作数栈顶部的对象引用存储到局部变量表的索引 1 处。
   L5  L5​ 标签出现在字节码中的第 5 行,它表示在 ​ALOAD 1​ 指令之后的位置。
    LINENUMBER 11 L5  表示字节码中的 ​L5​ 标签所在位置对应于源代码的第 11 行。
    ALOAD 1  将局部变量表索引 1 处的对象引用加载到操作数栈上。
    DUP      复制操作数栈顶部的对象引用,并将其放入操作数栈的顶部。
    ASTORE 2 将操作数栈顶部的对象引用存储到局部变量表索引 2 处。
    MONITORENTER  进入对象的监视器(获取对象锁)。
   L0  L0​ 标签出现在一系列指令的开始处。
    LINENUMBER 12 L0  表示源代码的行号为 12,对应于 ​L0​ 标签所在的位置。
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;  获取了 ​java.lang.System​ 类中的静态字段 ​out​,它是一个 ​java.io.PrintStream​ 类型的对象。
    LDC "synchronized demo ..."  将字符串常量 "synchronized demo ..." 加载到操作数栈上。
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V  调用了 ​PrintStream​ 类的 ​println​ 方法,将字符串常量打印到控制台。
   L6
    LINENUMBER 13 L6  表示源代码的行号为 13,对应于 ​L6​ 标签所在的位置。
    ALOAD 2  将局部变量表索引 2 处的对象引用加载到操作数栈上。
    MONITOREXIT  退出对象的监视器(释放对象锁)。
   L1
    GOTO L7  是一条无条件跳转指令,它会将程序的控制流程直接跳转到标签 ​L7​ 所指向的位置。
   L2
   FRAME FULL  表示字节码中的栈帧信息。 [[Ljava/lang/String; com/fei/multiThread/threadPool/SynchronizedDemo java/lang/Object] [java/lang/Throwable]
   表示当前方法的局部变量表中的数据类型。   表示当前方法可能抛出的异常类型。
    ASTORE 3  将操作数栈顶部的对象引用存储到局部变量表索引 3 处。
    ALOAD 2   将局部变量表索引 2 处的对象引用加载到操作数栈上。
    MONITOREXIT  退出对象的监视器(释放对象锁)。 以确保即使在发生异常时,锁也能被正确地释放。
   L3
    ALOAD 3  将局部变量表索引 3 处的对象引用加载到操作数栈上。
    ATHROW   抛出当前操作数栈顶部的异常对象。
   L7
    LINENUMBER 14 L7   表示源代码的行号为 14,对应于 ​L7​ 标签所在的位置。
   FRAME CHOP 1     指示当前方法调用的栈帧中,删除一个局部变量。这意味着局部变量表中的一个槽位被释放,可以用于存储其他数据。
    RETURN  表示从当前方法返回。
   L8
    LOCALVARIABLE args [Ljava/lang/String; L4 L8 0  表示方法的第一个局部变量名为 ​args​,类型为 ​java.lang.String[]​,它在字节码中的范围是从标签 ​L4​ 到 ​L8​,并且它在局部变量表中的索引为 0。
    LOCALVARIABLE synchronizedDemo Lcom/fei/multiThread/threadPool/SynchronizedDemo; L5 L8 1  表示方法的第二个局部变量名为 ​synchronizedDemo​,类型为 ​com.fei.multiThread.threadPool.SynchronizedDemo​,它在字节码中的范围是从标签 ​L5​ 到 ​L8​,并且它在局部变量表中的索引为 1。
    MAXSTACK = 2  表示该方法的操作数栈的最大深度为 2。
    MAXLOCALS = 4 表示该方法的局部变量表的最大容量为 4。
}

在Java字节码中,L0、L1、L2等标签(Label)通常用于表示代码块或分支的目标位置。这些标签用于标记字节码中的特定位置,以便在控制流程跳转时进行引用。

具体而言,L0、L1、L2等标签可以表示以下几种情况:

  1. 循环结构:在字节码中,循环结构通常使用 ​goto​指令或条件分支指令(如 ​ifeq​、​ifne​等)来实现。L0、L1、L2等标签可以用于标记循环的起始位置和结束位置,以便在控制流程跳转时进行引用。

  2. 分支结构:在字节码中,分支结构通常使用条件分支指令(如 ​ifeq​、​ifne​等)或 ​switch​指令来实现。L0、L1、L2等标签可以用于标记不同分支的目标位置,以便在控制流程跳转时进行引用。

  3. 异常处理:在字节码中,异常处理通常使用 ​try-catch-finally​块来实现。L0、L1、L2等标签可以用于标记 ​try​块、​catch​块和 ​finally​块的起始位置和结束位置,以便在发生异常时进行跳转和处理。

需要注意的是,L0、L1、L2等标签只是字节码中的符号,它们的具体名称和用途可能会根据编译器、优化器或其他工具的不同而有所变化。在字节码转换为可执行代码时,这些标签通常会被转换为具体的跳转指令或异常处理指令。因此,在阅读和理解字节码时,我们可以将L0、L1、L2等标签视为代码块或分支的目标位置的占位符。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值