Java类结构与类加载
1 Class文件结构
Java的规范分为Java语言规范和Java虚拟机规范,在设计之初就考虑了其他语言运行在Java虚拟机之上的可能性。
这块内容,看起来比较生涩乏味,也不能结合具体的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类型等等
字段表集合
字段表用于描述接口或者类中声明的变量。字段包含类级变量以及实例级变量(不包括局部变量),可以包括的信息有:字段的作用域(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 类的生命周期
2.2 类加载过程图
2.2 类加载机制--双亲委派(叫父委派更贴切)
类加载机制描述的选择哪个类加载器来加载类的过程。系统中默认的加载方式由下图所示。
基本过程:当调用一个类加载器的加载方法时,类加载器会先尝试让父类加载器来加载,如果父加载器不能加载,则自己尝试加载。
引申:注意这里的关系不是类的继承上的父子类关系,而是逻辑上的父子类关联关系。
我们业务代码默认都是AppClassLoader来加载,下面是改加载器加载路径的一个截图:主要包括jre\lib目录。target\classes目录,本地maven仓库。(当然这是没有打成jar包的时候,在idea运行时会去加载的目录,如果打成jar包后运行程序, 那么加载路径就是该jar包)
2.3 类加载完成后的状态
问题:
类加载器完成之后的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 }
加载图:
说明:
1 Class类中封装了类型的各种信息。在jvm中就是通过Class类的实例来获取每个Java类的所有信息的(类Class对象就是该类在内存中的代理)
2
整体流程图:
方法重载的实现