java 字节码分析_Java字节码分析

Java字节码分析

查看字节码详细内容 javap

javap

查看classFile的命令并将输出到file.txt

javap -v classFile > file.txt

参数

解释

‐version

版本信息

‐v

‐verbose 输出附加信息

‐l

输出行号和本地变量表

‐public

仅显示公共类和成员

‐protected

显示受保护的/公共类和成员

‐package

显示程序包/受保护的/公共类和成员 (默认)

‐p ‐private

显示所有类和成员

‐c

对代码进行反汇编

‐s

输出内部类型签名

‐sysinfo

显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)

‐constants

显示最终常量

‐classpath

指定查找用户类文件的位置

‐cp

指定查找用户类文件的位置

‐bootclasspath

覆盖引导类文件的位置

常量池描述符

Constant Type

Value

说明

CONSTANT_Class

7

类或接口的符号引用

CONSTANT_Fieldref

9

字段的符号引用

CONSTANT_Methodref

10

类中方法的符号引用

CONSTANT_InterfaceMethodref

11

接口中方法的符号引用

CONSTANT_String

8

字符串类型常量

CONSTANT_Integer

3

整形常量

CONSTANT_Float

4

浮点型常量

CONSTANT_Long

5

长整型常量

CONSTANT_Double

6

双精度浮点型常量

CONSTANT_NameAndType

12

字段或方法的符号引用

CONSTANT_Utf8

1

UTF-8编码的字符串

CONSTANT_MethodHandle

15

表示方法句柄

CONSTANT_MethodType

16

标志方法类型

CONSTANT_InvokeDynamic

18

表示一个动态方法调用点

字段描述符

FieldType term

Type

Interpretation

B

byte

signed byte

C

char

Unicode character code point in the BasicMultilingual Plane, encoded with UTF-16

D

double

double-precision floating-point value

F

float

single-precision floating-point value

I

int

integer

J

long

long integer

LClassName;

reference

an instance of class ClassName

S

short

signed short

Z

boolean

true or false

[

reference

one array dimension

方法描述符

方法:

Object m(int i, double d, Thread t) {...}

--->描述符

(IDLjava/lang/Thread;)Ljava/lang/Object;

解释:

传入(I 第一个参数int类型 D第二个参数double L第三个参数一个对象,后面是对象的描述java/lang/Thread;)输出Ljava/lang/Object;一个object对象

package JavaCore.JVM.ByteCode;

/*******************************************************************************

* @Copyright (C), 2018-2019,github:Swagger-Ranger

* @FileName: ByteCode_Test

* @Author: liufei32@outlook.com

* @Date: 2019/4/13 14:51

* @Description:

* @Aha-eureka:

*

* javap生成详细的命令

* javap -v ByteCode_Test.class > ByteCode_Test.txt

* 内容:

* 第一部分:显示了生成这个class的java源文件、版本信息、生成时间等。

* 第二部分:显示了该类中所涉及到常量池,共35个常量。

* 第三部分:显示该类的构造器,编译器自动插入的。

* 第四部分:显示了main方的信息。(这个是需要我们重点关注的)

*

* //第一部分

* Classfile /D:/Swagger-Ranger/git-workspace/Algorithms/out/production/Algorithms/JavaCore/JVM/ByteCode/ByteCode_Test.class

* Last modified 2019-4-13; size 617 bytes

* MD5 checksum 646edba623f52c83adb9e067841a1ffb

* Compiled from "ByteCode_Test.java"

* public class JavaCore.JVM.ByteCode.ByteCode_Test

* minor version: 0

* major version: 52

* flags: ACC_PUBLIC, ACC_SUPER

*

* //第二部分

* Constant pool:

*

* //这里在描述常量池时,所有的utf-8类型的都是值,即描述符的内容,而常量描述符的内容则用utf-8对于的常量序号引用来描述,并使用.:

* //等符号来拼接。比如:#1 = Methodref #5.#23 --层层引用还原#5.#23即为-->Class:java/lang/Object.""()V返回void---对没错就是后面注释的内容

*

* //常量的序号和类型 常量描述(使用字段描述符或方法描述符描述) 注释

*

* #1 = Methodref #5.#23 // java/lang/Object."":()V

* #2 = Fieldref #24.#25 // java/lang/System.out:Ljava/io/PrintStream;

* #3 = Methodref #26.#27 // java/io/PrintStream.println:(I)V

* #4 = Class #28 // JavaCore/JVM/ByteCode/ByteCode_Test

* #5 = Class #29 // java/lang/Object

* #6 = Utf8

* #7 = Utf8 ()V

* #8 = Utf8 Code

* #9 = Utf8 LineNumberTable

* #10 = Utf8 LocalVariableTable

* #11 = Utf8 this

* #12 = Utf8 LJavaCore/JVM/ByteCode/ByteCode_Test;

* #13 = Utf8 main

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

* #15 = Utf8 args

* #16 = Utf8 [Ljava/lang/String;

* #17 = Utf8 a

* #18 = Utf8 I

* #19 = Utf8 b

* #20 = Utf8 c

* #21 = Utf8 SourceFile

* #22 = Utf8 ByteCode_Test.java

* #23 = NameAndType #6:#7 // "":()V

* #24 = Class #30 // java/lang/System

* #25 = NameAndType #31:#32 // out:Ljava/io/PrintStream;

* #26 = Class #33 // java/io/PrintStream

* #27 = NameAndType #34:#35 // println:(I)V

* #28 = Utf8 JavaCore/JVM/ByteCode/ByteCode_Test

* #29 = Utf8 java/lang/Object

* #30 = Utf8 java/lang/System

* #31 = Utf8 out

* #32 = Utf8 Ljava/io/PrintStream;

* #33 = Utf8 java/io/PrintStream

* #34 = Utf8 println

* #35 = Utf8 (I)V

*

* //第三部分该类的构造器,编译器自动插入的。

* {

* public JavaCore.JVM.ByteCode.ByteCode_Test();

* descriptor: ()V //构造函数描述,()V-无传入参数并返回空

* flags: ACC_PUBLIC

* Code:

* stack=1, locals=1, args_size=1

* 0: aload_0

* 1: invokespecial #1 // Method java/lang/Object."":()V

* 4: return

* LineNumberTable:

* line 12: 0

* LocalVariableTable:

* Start Length Slot Name Signature

* 0 5 0 this LJavaCore/JVM/ByteCode/ByteCode_Test;

*

* //第四部分 main方的信息。(这个是需要我们重点关注的)

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

* descriptor: ([Ljava/lang/String;)V //方法描述,([Ljava/lang/String;)传入一个string一维数组参数;V-返回空

* flags: ACC_PUBLIC, ACC_STATIC //方法修饰符:ACC_PUBLIC :public, ACC_STATIC :static

* Code: //代码块

* stack=2, locals=4, args_size=1 //首先对Code作了统计,stack操作栈(任何操作都先要把值放入操作栈才能操作)有2个,locals本地变量有4个,args_size参数个数有1个

* 0: iconst_2 //将数字2值压入操作栈,位于栈的最上面

* 1: istore_1 //从操作栈中弹出一个元素(数字2),放入到本地变量表中,位于下标为1的位置(下标为0的是this)

* 2: iconst_3 //将数字5值压入操作栈,位于栈的最上面

* 3: istore_2 //从操作栈中弹出一个元素(5),放入到本地变量表中,位于第下标为2个位置

* 4: iload_2 //将本地变量表中下标为2的位置元素压入操作栈(5)

* 5: iload_1 //将本地变量表中下标为1的位置元素压入操作栈(2)

* 6: isub //操作栈中的2个数字相减

* 7: istore_3 // 将相减的结果压入到本地本地变量表中,位于下标为3的位置

* // 开始执行打印语句,那首先要找到打印的内容,通过getstatic #2找到对应的常量即常量池中的#2常量,即可找到对应的引用

* 8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

* 11: iload_3 //将本地变量表中下标为3的位置元素压入操作栈(3)

* // 通过#3号找到对应的常量,然后invokevirtual去执行#3= Methodref 方法引用,即可找到对应的引用,进行方法调用

* 12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V

* 15: return //返回

* LineNumberTable: //这里是源码行号和字节码步骤作一一对应,当然因为我将注释复制了过来所以这里源码行号有改变

* line 15: 0

* line 16: 2

* line 17: 4

* line 18: 8

* line 19: 15

* LocalVariableTable: //本地变量表

* 槽位 变量名 字段描述符

* Start Length Slot Name Signature

* 0 16 0 args [Ljava/lang/String;

* 2 14 1 a I

* 4 12 2 b I

* 8 8 3 c I

* }

* SourceFile: "ByteCode_Test.java"

*******************************************************************************/

public class ByteCode_Test {

public static void main( String[] args ) {

int a = 2;

int b = 3;

int c = b - a;

System.out.println(c);

}

}

实例分析

i++与++i

package JavaCore.JVM.ByteCode;

/*******************************************************************************

* @Copyright (C), 2018-2019,github:Swagger-Ranger

* @FileName: ByteCode_iplusplus_plusplusi

* @Author: liufei32@outlook.com

* @Date: 2019/4/14 0:04

* @Description: i++和++i的具体字节码

* @Aha-eureka:

*******************************************************************************/

public class ByteCode_iplusplus_plusplusi {

public void method1() {

int i = 5;

int a = i++;

System.out.println(a);

}

public void method2() {

int i = 5;

int a = ++i;

System.out.println(a);

}

public static void main( String[] args ) {

new ByteCode_iplusplus_plusplusi().method1();

new ByteCode_iplusplus_plusplusi().method2();

}

}

/**

* 命令:javap -v ByteCode_iplusplus_plusplusi.class > ByteCode_iplusplus_plusplusi.txt

*

* Classfile /D:/Swagger-Ranger/git-workspace/Algorithms/out/production/Algorithms/JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi.class

* Last modified 2019-4-14; size 876 bytes

* MD5 checksum 6619df3d2429d5c853b4d1972b1e6504

* Compiled from "ByteCode_iplusplus_plusplusi.java"

* public class JavaCore.JVM.ByteCode.ByteCode_iplusplus_plusplusi

* minor version: 0

* major version: 52

* flags: ACC_PUBLIC, ACC_SUPER

* Constant pool:

* #1 = Methodref #8.#27 // java/lang/Object."":()V

* #2 = Fieldref #28.#29 // java/lang/System.out:Ljava/io/PrintStream;

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

* #4 = Class #32 // JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi

* #5 = Methodref #4.#27 // JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi."":()V

* #6 = Methodref #4.#33 // JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi.method1:()V

* #7 = Methodref #4.#34 // JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi.method2:()V

* #8 = Class #35 // java/lang/Object

* #9 = Utf8

* #10 = Utf8 ()V

* #11 = Utf8 Code

* #12 = Utf8 LineNumberTable

* #13 = Utf8 LocalVariableTable

* #14 = Utf8 this

* #15 = Utf8 LJavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi;

* #16 = Utf8 method1

* #17 = Utf8 i

* #18 = Utf8 I

* #19 = Utf8 a

* #20 = Utf8 method2

* #21 = Utf8 main

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

* #23 = Utf8 args

* #24 = Utf8 [Ljava/lang/String;

* #25 = Utf8 SourceFile

* #26 = Utf8 ByteCode_iplusplus_plusplusi.java

* #27 = NameAndType #9:#10 // "":()V

* #28 = Class #36 // java/lang/System

* #29 = NameAndType #37:#38 // out:Ljava/io/PrintStream;

* #30 = Class #39 // java/io/PrintStream

* #31 = NameAndType #40:#41 // println:(I)V

* #32 = Utf8 JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi

* #33 = NameAndType #16:#10 // method1:()V

* #34 = NameAndType #20:#10 // method2:()V

* #35 = Utf8 java/lang/Object

* #36 = Utf8 java/lang/System

* #37 = Utf8 out

* #38 = Utf8 Ljava/io/PrintStream;

* #39 = Utf8 java/io/PrintStream

* #40 = Utf8 println

* #41 = Utf8 (I)V

* {

* public JavaCore.JVM.ByteCode.ByteCode_iplusplus_plusplusi();

* descriptor: ()V

* flags: ACC_PUBLIC

* Code:

* stack=1, locals=1, args_size=1

* 0: aload_0

* 1: invokespecial #1 // Method java/lang/Object."":()V

* 4: return

* LineNumberTable:

* line 12: 0

* LocalVariableTable:

* Start Length Slot Name Signature

* 0 5 0 this LJavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi;

*

* public void method1(); //i++

* descriptor: ()V

* flags: ACC_PUBLIC

* Code:

* stack=2, locals=3, args_size=1

* 0: iconst_5 //将5压入操作栈

* 1: istore_1 //从操作栈中弹出变量并保存到下标为1的本地变量表

* 2: iload_1 //加载下标为1的本地变量表中的变量到操作栈

* 3: iinc 1, 1 //将本地变量表中下标为1的变量加1,这句命令iinc直接操作本地变量表并跟了两个参数1,1

* 6: istore_2 //将操作栈中的变量(值为1)弹出并保存到下标为2的本地变量表

* 7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

* 10: iload_2 //将本地变量表中下标为2的变量加载到操作栈

* 11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V //这里打印传参I就是操作栈中的变量i(值为1)

* 14: return

* LineNumberTable:

* line 15: 0

* line 16: 2

* line 17: 7

* line 18: 14

* LocalVariableTable:

* Start Length Slot Name Signature

* 0 15 0 this LJavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi;

* 2 13 1 i I

* 7 8 2 a I

*

* public void method2(); //++i

* descriptor: ()V

* flags: ACC_PUBLIC

* Code:

* stack=2, locals=3, args_size=1

* 0: iconst_5 //将5压入操作栈

* 1: istore_1 //从操作栈中弹出变量并保存到下标为1的本地变量表

* 2: iinc 1, 1 //将本地变量表中下标为1的变量加1,这句命令iinc直接操作本地变量表并跟了两个参数1,1

* 5: iload_1 //加载下标为1的本地变量表中的变量到操作栈

* 6: istore_2

* 7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

* 10: iload_2

* 11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V

* 14: return

* LineNumberTable:

* line 21: 0

* line 22: 2

* line 23: 7

* line 24: 14

* LocalVariableTable:

* Start Length Slot Name Signature

* 0 15 0 this LJavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi;

* 2 13 1 i I

* 7 8 2 a I

*

* 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: new #4 // class JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi

* 3: dup

* 4: invokespecial #5 // Method "":()V

* 7: invokevirtual #6 // Method method1:()V

* 10: new #4 // class JavaCore/JVM/ByteCode/ByteCode_iplusplus_plusplusi

* 13: dup

* 14: invokespecial #5 // Method "":()V

* 17: invokevirtual #7 // Method method2:()V

* 20: return

* LineNumberTable:

* line 27: 0

* line 28: 10

* line 29: 20

* LocalVariableTable:

* Start Length Slot Name Signature

* 0 21 0 args [Ljava/lang/String;

* }

* SourceFile: "ByteCode_iplusplus_plusplusi.java"

*/

619c10bb08338be306f5a97801714308.png

区别:

i++

只是在本地变量中对数字做了相加,并没有将数据压入到操作栈 将前面拿到的数字1,

再次从操作栈中拿到,压入到本地变量中

++i

将本地变量中的数字做了相加,并且将数据压入到操作栈 将操作栈中的数据,

再次压入到本地变量中

本博客为Swagger-Ranger的笔记分享,文章会持续更新

文中源码地址: https://github.com/Swagger-Ranger

欢迎交流指正,如有侵权请联系作者确认删除: liufei32@outlook.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值