我是靠谱客的博主 陶醉滑板,最近开发中收集的这篇文章主要介绍字节码指令2.1 入门 2.2 javap 工具 2.3 图解方法执行流程 ,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

2.1 入门

2.2 javap 工具

2.3 图解方法执行流程

1)原始 java 代码

2)编译后的字节码文件

3)常量池载入运行时常量池

4)方法字节码载入方法区

5)main 线程开始运行,分配栈帧内存

6)执行引擎开始执行字节码

bipush 10

istore_1

ldc #3

istore_2

iload_2

iadd

istore_3

getstatic #4

iload_3

invokevirtual #5

return


2.1 入门

接着上一节,研究一下两组字节码指令,一个是

//构造方法的字节码指令

public cn.itcast.jvm.t5.HelloWorld();

2a b7 00 01 b1

  1. 2a => aload_0 加载 slot 0 的局部变量,即 this,做为下面的 invokespecial 构造方法调用的参数
  2. b7 => invokespecial 预备调用构造方法,哪个方法呢?
  3. 00 01 引用常量池中 #1 项,即【 Method java/lang/Object."":()V 】
  4. b1 表示返回

另一个是 public static void main(java.lang.String[]); 主方法的字节码指令

b2 00 02 12 03 b6 00 04 b1

  1. b2 => getstatic 用来加载静态变量,哪个静态变量呢?
  2. 00 02 引用常量池中 #2 项,即【Field java/lang/System.out:Ljava/io/PrintStream;】
  3. 12 => ldc 加载参数,哪个参数呢?
  4. 03 引用常量池中 #3 项,即 【String hello world】
  5. b6 => invokevirtual 预备调用成员方法,哪个方法呢?
  6. 00 04 引用常量池中 #4 项,即【Method java/io/PrintStream.println:(Ljava/lang/String;)V】
  7. b1 表示返回

请参考

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5

2.2 javap 工具

自己分析类文件结构太麻烦了,Oracle 提供了 javap 工具来反编译 class 文件

[root@localhost ~]# javap -v HelloWorld.class

Classfile /root/HelloWorld.class

Last modified Jul 7, 2019; size 597 bytes

MD5 checksum 361dca1c3f4ae38644a9cd5060ac6dbc

Compiled from "HelloWorld.java"

public class cn.itcast.jvm.t5.HelloWorld

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

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

#2 = Fieldref #22.#23 //

java/lang/System.out:Ljava/io/PrintStream;

#3 = String #24 // hello world

#4 = Methodref #25.#26 // java/io/PrintStream.println:

(Ljava/lang/String;)V

#5 = Class #27 // cn/itcast/jvm/t5/HelloWorld

#6 = Class #28 // java/lang/Object

#7 = Utf8 <init>

#8 = Utf8 ()V

#9 = Utf8 Code

#10 = Utf8 LineNumberTable

#11 = Utf8 LocalVariableTable

#12 = Utf8 this

#13 = Utf8 Lcn/itcast/jvm/t5/HelloWorld;

#14 = Utf8 main

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

#16 = Utf8 args

#17 = Utf8 [Ljava/lang/String;

#18 = Utf8 MethodParameters

#19 = Utf8 SourceFile

#20 = Utf8 HelloWorld.java

#21 = NameAndType #7:#8 // "<init>":()V

#22 = Class #29 // java/lang/System

#23 = NameAndType #30:#31 // out:Ljava/io/PrintStream;

#24 = Utf8 hello world

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

#26 = NameAndType #33:#34 // println:(Ljava/lang/String;)V

#27 = Utf8 cn/itcast/jvm/t5/HelloWorld

#28 = Utf8 java/lang/Object

#29 = Utf8 java/lang/System

#30 = Utf8 out

#31 = Utf8 Ljava/io/PrintStream;

#32 = Utf8 java/io/PrintStream

#33 = Utf8 println

#34 = Utf8 (Ljava/lang/String;)V

{

public cn.itcast.jvm.t5.HelloWorld();

descriptor: ()V

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 4: 0

LocalVariableTable:

Start Length Slot Name Signature

0 5 0 this Lcn/itcast/jvm/t5/HelloWorld;

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

descriptor: ([Ljava/lang/String;)V

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=1, args_size=1

0: getstatic #2 // Field

java/lang/System.out:Ljava/io/PrintStream;

3: ldc #3 // String hello world

5: invokevirtual #4 // Method

java/io/PrintStream.println:(Ljava/lang/String;)V

8: return

LineNumberTable:

line 6: 0

line 7: 8

LocalVariableTable:

Start Length Slot Name Signature

0 9 0 args [Ljava/lang/String;

MethodParameters:

Name Flags

args

}

2.3 图解方法执行流程

1)原始 java 代码

package cn.itcast.jvm.t3.bytecode;
/**
* 演示 字节码指令 和 操作数栈、常量池的关系
*/
public class Demo3_1 {
	public static void main(String[] args) {
	int a = 10;
	int b = Short.MAX_VALUE + 1;
	int c = a + b;
	System.out.println(c);
	}
}

2)编译后的字节码文件

[root@localhost ~]# javap -v Demo3_1.class

Classfile /root/Demo3_1.class

Last modified Jul 7, 2019; size 665 bytes

MD5 checksum a2c29a22421e218d4924d31e6990cfc5

Compiled from "Demo3_1.java"

public class cn.itcast.jvm.t3.bytecode.Demo3_1

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

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

#2 = Class #27 // java/lang/Short

#3 = Integer 32768

#4 = Fieldref #28.#29 //

java/lang/System.out:Ljava/io/PrintStream;

#5 = Methodref #30.#31 // java/io/PrintStream.println:(I)V

#6 = Class #32 // cn/itcast/jvm/t3/bytecode/Demo3_1

#7 = Class #33 // java/lang/Object

#8 = Utf8 <init>

#9 = Utf8 ()V

#10 = Utf8 Code

#11 = Utf8 LineNumberTable

#12 = Utf8 LocalVariableTable

#13 = Utf8 this

#14 = Utf8 Lcn/itcast/jvm/t3/bytecode/Demo3_1;

#15 = Utf8 main

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

#17 = Utf8 args

#18 = Utf8 [Ljava/lang/String;

#19 = Utf8 a

#20 = Utf8 I

#21 = Utf8 b

#22 = Utf8 c

#23 = Utf8 MethodParameters

#24 = Utf8 SourceFile

#25 = Utf8 Demo3_1.java

#26 = NameAndType #8:#9 // "<init>":()V

#27 = Utf8 java/lang/Short

#28 = Class #34 // java/lang/System

#29 = NameAndType #35:#36 // out:Ljava/io/PrintStream;

#30 = Class #37 // java/io/PrintStream

#31 = NameAndType #38:#39 // println:(I)V

#32 = Utf8 cn/itcast/jvm/t3/bytecode/Demo3_1

#33 = Utf8 java/lang/Object

#34 = Utf8 java/lang/System

#35 = Utf8 out

#36 = Utf8 Ljava/io/PrintStream;

#37 = Utf8 java/io/PrintStream

#38 = Utf8 println

#39 = Utf8 (I)V

{

public cn.itcast.jvm.t3.bytecode.Demo3_1();

descriptor: ()V

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 6: 0

LocalVariableTable:

Start Length Slot Name Signature

0 5 0 this Lcn/itcast/jvm/t3/bytecode/Demo3_1;

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

descriptor: ([Ljava/lang/String;)V

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=4, args_size=1

0: bipush 10

2: istore_1

3: ldc #3 // int 32768

5: istore_2

6: iload_1

7: iload_2

8: iadd

9: istore_3

10: getstatic #4 // Field

java/lang/System.out:Ljava/io/PrintStream;

13: iload_3

14: invokevirtual #5 // Method

java/io/PrintStream.println:(I)V

17: return

LineNumberTable:

line 8: 0

line 9: 3

line 10: 6

line 11: 10

line 12: 17

LocalVariableTable:

Start Length Slot Name Signature

0 18 0 args [Ljava/lang/String;

3 15 1 a I

6 12 2 b I

10 8 3 c I

MethodParameters:

Name Flags

args

}

3)常量池载入运行时常量池

4)方法字节码载入方法区

5)main 线程开始运行,分配栈帧内存

(stack=2,locals=4)

6)执行引擎开始执行字节码

bipush 10

将一个 byte 压入操作数栈(其长度会补齐 4 个字节),类似的指令还有

sipush 将一个 short 压入操作数栈(其长度会补齐 4 个字节)

ldc 将一个 int 压入操作数栈

ldc2_w 将一个 long 压入操作数栈(分两次压入,因为 long 是 8 个字节)

这里小的数字都是和字节码指令存在一起,超过 short 范围的数字存入了常量池

istore_1

将操作数栈顶数据弹出,存入局部变量表的 slot 1

ldc #3

从常量池加载 #3 数据到操作数栈

注意 Short.MAX_VALUE 是 32767,所以 32768 = Short.MAX_VALUE + 1 实际是在编译期间计算

好的

istore_2

iload_1

iload_2

iadd

istore_3

getstatic #4

iload_3

invokevirtual #5

找到常量池 #5 项

定位到方法区 java/io/PrintStream.println:(I)V 方法

生成新的栈帧(分配 locals、stack等)

传递参数,执行新栈帧中的字节码

执行完毕,弹出栈帧

清除 main 操作数栈内容

return

完成 main 方法调用,弹出 main 栈帧

程序结束

最后

以上就是陶醉滑板为你收集整理的字节码指令2.1 入门 2.2 javap 工具 2.3 图解方法执行流程 的全部内容,希望文章能够帮你解决字节码指令2.1 入门 2.2 javap 工具 2.3 图解方法执行流程 所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部