一.字节码查看
将.java源文件编译成.class二进制字节码文件,运行该字节码文件
1.将class字节码文件内容输出到文本文件当中
javap -v xxx.class > xxx.txt
第一个部分:
显示生成class的java源文件的基本信息
Classfile /C:/Users/FLC/Desktop/授课内容/授课案例/Y2170/day22/jvm_project/jvm_day01/target/classes/com/wdksoft/ClassTest.class
Last modified 2020-3-11; size 585 bytes
MD5 checksum 39fa2636495e5b4bf08da6decc537381
Compiled from "ClassTest.java"
public class com.wdksoft.ClassTest
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
第二个部分:显示该类所涉及到的常量池,共有35个常量
Constant pool:
#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 // com/wdksoft/ClassTest
#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 Lcom/wdksoft/ClassTest;
#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 ClassTest.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 com/wdksoft/ClassTest
#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 com.wdksoft.ClassTest();
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 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wdksoft/ClassTest;
第四部分:显示main方法的信息
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V 方法的描述,V代表返回值为void
flags: ACC_PUBLIC, ACC_STATIC 方法修饰符 public static
Code:
stack=2, locals=4, args_size=1 stack代表操作栈的大小 locals本地变量表大小 args_size代表参数个数
0: iconst_2 将数据2压入到操作栈当中,位于栈顶
1: istore_1 从操作栈当中弹出一个数据,放到本地变量表当中,下标为1,0是this,操作栈当中数据清空
2: iconst_5 将数据5压入到操作栈当中,位于栈顶
3: istore_2 从操作栈当中弹出一个数据,放到本地变量表当中,下标为2,0是this,操作栈当中数据清空
4: iload_2 将本地变量表中的下标为2的数据压入到操作站
5: iload_1 将本地变量表中的下标为1的数据压入到操作站
6: isub 将操作栈中的两个数据相减
7: istore_3 将相减的结果压入到本地本地变量表当中,下标为3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_3 将本地变量表中下标为3的数据压入到操作站
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: return 返回
LineNumberTable: 行号列表
line 5: 0
line 6: 2
line 7: 4
line 8: 8
line 9: 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
二.动态字节技术
在程序运行或者编译时期,通过动态字节码技术对类新增,删除,修改类的内部结构,包括字段和方法
动态字节码技术应用场景:AOP,Lombok,动态修改class文件等等
字节码操作类库:
1.BCEL
2.ASM:轻量级的Java字节码操作框架,SpringAOP底层基于ASM字节码技术
3.CGLIB 基于ASM
4.javassist
通过javap命令查看class文件的字节码内容
1.1创建一个简单的测试类:
public class Test {
public static void main(String[] args) {
int a=2;
int b=5;
int c=b-a;
System.out.println(c);
}
}
1.2 cmd打开窗口,使用如下命令:
javap ‐v Test.class > Test.txt
1.3查看Test01.txt文件,内容如下:
Classfile /G:/学习/Y2/Test/Test01.class
Last modified 2020-3-9; size 576 bytes
MD5 checksum e263d731887a9c6376ddab948c1efa19
Compiled from "Test01.java"
public class com.my.Test.Test01
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#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 // com/wn/Test/Test01
#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 Lcom/wn/Test/Test01;
#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 Test01.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 com/wn/Test/Test01
#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 com.my.Test.Test01();
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 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wn/Test/Test01;
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: iconst_2
1: istore_1
2: iconst_5
3: istore_2
4: iload_2
5: iload_1
6: isub
7: istore_3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_3
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: return
LineNumberTable:
line 5: 0
line 6: 2
line 7: 4
line 8: 8
line 9: 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: "Test01.java"
二.代码优化
所谓代码优化是指对程序代码进行等价(指不改变程序的运行结果)变换。程序代码可以是中间代码(如四元式代码),也可以是目标代码。等价的含义是使得变换后的代码运行结果与变换前代码运行结果相同。优化的含义是最终生成的目标代码短(运行时间更短、占用空间更小),时空效率优化。原则上,优化可以在编译的各个阶段进行,但最主要的一类是对中间代码进行优化,这类优化不依赖于具体的计算机。
在不改变程序运行效果的前提下,对被编译的程序进行等价变换,使之能生成更加高效的目标代码。
明确一个概念,对方法的调用,即使方法中只有一句 语句,也是有消耗的。
for (int i = 0; i < list.size(); i++)
{...}
建议替换为:
int length = list.size();
for (int i = 0, i < length; i++)
{...}