JVM虚拟机笔记(2)

时间:2022-12-26 22:16:22

Java类结构与类加载

1 Class文件结构

  Java的规范分为Java语言规范和Java虚拟机规范,在设计之初就考虑了其他语言运行在Java虚拟机之上的可能性。

JVM虚拟机笔记(2)

 

这块内容,看起来比较生涩乏味,也不能结合具体的Class文件来看(反编译出来的内容不能完全体现出这个Class结构),具体可以参看下面的文章,本文就简单说明一下

  http://wiki.jikexueyuan.com/project/java-vm/class.html 

  https://zhuanlan.zhihu.com/p/25823310

魔数与版本

  每个Class文件头的4个字节称为魔术,是Class文件的身份标识。第5,6两个字节是次版本号(Minor Version),第7、8两个字节是主版本号(Major Version)

常量池

  存放文本字符串,声明为final的常量值、类和接口的全限定名、字段名称和描述符、方法名称和描述符等

访问标志

  标识这个Class是类还是接口、是否定义为public类型、是否定义为abstract类型等等

JVM虚拟机笔记(2)

字段表集合

  字段表用于描述接口或者类中声明的变量。字段包含类级变量以及实例级变量(不包括局部变量),可以包括的信息有:字段的作用域(public、private、protected)、是实例变量还是类变量(static修饰)、可变性(final)、并发可见性(volatile修饰)

可否被序列化(transient修饰)、字段数据类型、字段名称等

 

方法表集合

类似于字段集合表,方法表集合可以包括的信息有:访问标志、名称索引、描述符索引、属性表集合

 

属性表集合

在Class文件、字段表、方法表都可以携带自己的属性表集合,已用于描述某些场景专有的信息。java程序方法体重的代码经过javac编译器处理之后,最终变为字节码指令存储在Code属性内。

 

2 类加载

 当一个classLoder启动的时候,classLoader的生存地点在jvm中的堆,然后它会去主机硬盘上将A.class装载到jvm的方法区,方法区中的这个字节文件会被虚拟机拿来new A字节码(),然后在堆内存生成了一个A字节码的对象,然后A字节码这个内存文件有两个引用一个指向A的class对象,一个指向加载自己的classLoader。

2.1 类的生命周期

JVM虚拟机笔记(2)

 

2.2 类加载过程图

JVM虚拟机笔记(2)

 

2.2 类加载机制--双亲委派(叫父委派更贴切)

类加载机制描述的选择哪个类加载器来加载类的过程。系统中默认的加载方式由下图所示。

基本过程:当调用一个类加载器的加载方法时,类加载器会先尝试让父类加载器来加载,如果父加载器不能加载,则自己尝试加载。

JVM虚拟机笔记(2)

 

引申:注意这里的关系不是类的继承上的父子类关系,而是逻辑上的父子类关联关系。

JVM虚拟机笔记(2)

我们业务代码默认都是AppClassLoader来加载,下面是改加载器加载路径的一个截图:主要包括jre\lib目录。target\classes目录,本地maven仓库。(当然这是没有打成jar包的时候,在idea运行时会去加载的目录,如果打成jar包后运行程序, 那么加载路径就是该jar包)

JVM虚拟机笔记(2)

 

 

 

2.3 类加载完成后的状态

JVM虚拟机笔记(2)

 

 

问题:

类加载器完成之后的Class对象有什么作用?

类加载器是如何加载到jvm中,普通类为啥要有类加载器来加载?

 

参考:

 http://wiki.jikexueyuan.com/project/java-vm/class-loading-mechanism.html

 https://www.cnblogs.com/duanxz/p/3728737.html

3 方法调用

代码示例

 1 //main方法
 2 public class HelloWorldDemo2 {
 3 
 4 
 5     public static void main(String[] args) {
 6         Caller caller = new Caller();
 7         caller.callerMethod();
 8     }
 9 }
10 
11 
12 //主类
13 public class Caller {
14 
15     public static int a = 1;
16 
17     public static void staticMethod() {
18         System.out.println("caller static method");
19     }
20 
21         public void callerMethod() {
22         int b = a;
23         System.out.println(b+a);
24         staticMethod();
25         Father father = new Father();
26         Father son = new Son();
27         father.hardChoice(1);
28         father.hadChoice("father");
29         father.sayHello();
30         son.hardChoice(1);
31         son.hadChoice("son");
32         son.sayHello();
33     }
34 }
35 
36 
37 //调用类父类
38 public class Father {
39 
40     public void hardChoice(int a) {
41         System.out.println("father choose int: " + a);
42     }
43 
44     public void hadChoice(String b) {
45         System.out.println("father choose str: " + b);
46     }
47 
48     public void sayHello() {
49         System.out.println("father say hello");
50     }
51     
52 }
53 
54 //调用类子类
55 public class Son extends Father {
56 
57     @Override
58     public void hardChoice(int a) {
59         System.out.println("son choose int:" + a);
60     }
61 
62 }

 

 

 

 

加载图:

 

JVM虚拟机笔记(2)

 

 说明:

1 Class类中封装了类型的各种信息。在jvm中就是通过Class类的实例来获取每个Java类的所有信息的(类Class对象就是该类在内存中的代理)
2

整体流程图:
JVM虚拟机笔记(2)

 

 

方法重载的实现