1.Class Files:将.java文件编译为.class文件
2.Class Loader Subsystem:将.class文件加载到jvm虚拟机中去。
3.Runtime Data Areas:运行时内存区域的划分。
4.Execition Engine:执行引擎,包括两部分。GC:垃圾回收器。JIT:java的编译。
5.Native Method Interface:与硬件进行交互的接口。
1)Class File:
Class字节码文件是jvm认识的一种文件,里面的地址都是逻辑地址。最后需要运行在操作系统中,操作系统只能识别真实的物理地址。此时需要动态链接,就是在运行时动态地绑定对象,对象地址。
Class字节码文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何的分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必须数据。
Class字节码文件只有两种数据类型:无符号数(u)和表(info)
下面我们看一下.class文件。
下面的代码为string和stringbuffer的区别以及try和finally哪个更加优先。
public class Test {
public static void m1() {
String str = "";
for (int i = 0; i < 10; i++) {
str = str + "xxo.";
}
System.out.println(str);
}
public static void m2() {
StringBuffer str = new StringBuffer();
for (int i = 0; i < 10; i++) {
str.append("xxo,");
}
System.out.println(str);
}
public static String m3() {
String str = "hello";
try {
return str;
} finally {
str = "nx";
}
}
public static void main(String[] args){
System.out.println(m3());
}
}
运行以后在out中找到对应的class文件,右键打开控制台打开控制台之后输入javap -verbose Test.class
javap:字节码的注记指令。
verbose:输出附加信息。
Constant pool:常量池。
方法m1的注记符提示
第8条指令为if-icmpge if(如果) i cmp(比较)ge(>=)这条指令为条件判断语句
第34条指令为goto(跳转)
第八条到第34条指令之间为for语句块的内容
String的创建在第11条指令的new调用了class java/lang/StringBuilder 第15行invokespecial调用了Method java/lang/StringBuilder.""😦)V
而我们同样的来看方法m2,在里面没有new也没有invokespecial,而是第19行指令使用了invokevirtual 并且调用了Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
由此可见String和StringBuffer在class层面的区别。
接下来我们研究一下try和finally的优先级。
如下图所示,String str = “hello”; 在class中的操作如下(第0条指令ldc #14 是将“hello”放入常量池14号位置中,第二条指令astore_0将查找的常量存储到0号变量上第三条指令aload_0将0号变量的值进行压栈,第四条指令astore_1再将常量存储到1号变量上。)第8条指令将hello压栈,第10条指令areturn将hello返回。所以返回的值为hello不是nx。try比finally优先级高。
如果想要具体了解各个指令的含义可以上这个网站查看
https://docs.oracle.com/javase/specs/index.html
这个是java的虚拟机规范
接着打开第四章内容
它的左侧栏有各种注记符的具体内容,点击即可。
下图为class文件的结构。我会通过二进制流来展示一下class文件。
以下面的代码产生的class文件举例。
public class IntTest {
public static void main(String[] args){
int a = 1;
int b = 200;
int c = a+b;
System.out.println(c);
}
}
打开控制台之后输入javap -verbose IntTest.class
右键在文件夹中打开class文件,使用notepad++打开后如图(你九成九看不懂)
这里需要你点开上面栏中的插件,安装Hex-editor(用16位显示),使用插件后打开如下。我将给出一部分的解读。
对照这个官方文档来看
首先是u4,4个字节的无符号位数表示的magic(魔法数,是校验位检验这个文档是否为class文档)这里是ca fe ba be
u2 minor_version;00 00
u2 major_version;00 34(注意是16位的,换算成十进制为52)
这两个代表的是class文件的副版本和主版本。
控制台中看到
u2 constant_pool_count;00 24 (十进制为00 36)是常量池的个数。
cp_info constant_pool[constant_pool_count-1];00 24(十进制为00 36)常量池个数减一。
从1开始到35共35个。
具体解析cp_info,ctrl+f搜索官方文档
这里规定了cp_info的格式。u1_tag; 和 u1_info[];是个复合格式。共35个这种复合格式。根据不同tag值,info也不同
u1_tag 0a(10)为CONSTANT_Methodref,继续ctrl+f页面内查找CONSTANT_Methodref
可见u1_info格式为
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
这里需要读u2 class_index;00 05(5)以及 u2 name_and_type_index; 00 17(23),在控制台中看到对应。
接下来的8位码解析操作基本雷同就不再赘述。