Java虚拟机是如何加载Java类的?
大体流程图:
Java 加载java类主要有5个步骤:
1. 加载
2. 校验
3. 准备
4. 解析
5. 初始化
加载:首先通过类加载器查找java编译后的字节码文件(.class),然后把该文件加载到方法区中;这时方法区中应该有一个代表该字节码文件的对象;PS:代表字节码的这个对象是存放在内存中,还是方法区中有待商榷!!!
因为内存是存放对象的地方,而类也是属于一个对象,而方法区中存放的是类的相关信息;这个地方我有点拿不准!!!我个人认为是方法区
校验:就是对字节码class文件进行验证,只有符合jvm规范的文件才会校验通过;
准备:类的准备阶段会涉及类的初始化,也会正式给类变量分配内存并设置类变量的初始值,这些变量所使用的内存都将在方法区分配(注意这里说的是类变量,也就是static修饰符修饰的变量)
比如在 Public static int value = 123 ,在执行准备阶段的时候,会给value分配内存并设置初始值0, 而不是我们想象中的123,等到初始化时才会真正给value 赋值123;
解析:class文件里面包含的是java类的全名,接口的全名和字段名称描述符,方法的名称和描述符等信息;数据加载到jvm内存的方法区之后,被称做是符号引用。而把这些类的全限定名,方法描述符等转化为jvm可以直接获取的jvm内存地址,指针等的过程,就是解析;
直白一点:就是给类,接口,方法分配jvm能识别的内存地址;到时用的时候好能找到!!!
初始化:在编译的时候,编译器会自动收集类中的所有静态变量(类变量)和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是根据语句在java代码中的顺序决定的。收集完成之后,会编译成java类的 static{} 方法,java虚拟机则会保证一个类的static{} 方法在多线程或者单线程环境中正确的执行,并且只执行一次。在执行的过程中,便完成了类变量的初始化。值得说明的是,如果我们的java类中,没有显式声明static{}块,如果类中有静态变量,编译器会默认给我们生成一个static{}方法;
从上面的介绍中可以发现,类的初始化是完成有关于类的一些信息(static标记的类成员变量)
那么实例变量是什么时候完成初始化的呢?
其实是和静态变量的过程是类似的,但是时间和地点都不同,
它是在你创建这个类的对象时完成的,其实也不难理解,因为static修饰的是属于类的,而实例变量是属于实际对象的,所以在创建对象的时候才在构造方法里面初始化!!!
对象创建过程以及对象初始化过程:
1. 首先创建对象,然后在堆中为该对象分配内存;注意:这时这个对象的成员变量都是原始的初始值,即:int i = 2;i的值为初始值0;对象的话就为null
2. 然后在构造函数中为成员变量赋值;即:i = 2;(没有构造函数会自动生成构造函数);
类加载器种类?
上面我们提到了加载class文件时,用到了类加载器,那么类加载器是哪儿来的?以及有多少种类加载器?
类加载器的种类:
1. 启动类加载器:负责加载最最基础的类;例如:jre lib包下面的jar包中的类
2. 扩展类加载器:负责加载相对次要,但又通用的类,比如存放在jre lib/ext下面的jar包中的类
3. 应用类加载器:负责加载应用程序下的类;即:classath路径下的类
类加载器的加载策略?
类加载器加载类的策略:双亲委派模式
双亲委派模式是什么鬼?要说起这个双亲委派模式,还的说说类的加载顺序:启动类加载器 =》扩展类加载器 =》 应用类加载器;双亲委派模式说的直白一点就是已经被类加载器加载过的类,后面的类加载器就不加载了,这样的好处就是类只会被加载一次;
类什么时候会被加载?
1. new 对象时
2. 调用静态方法,静态字段时
3. 子类加载之前会先加载父类
4. 使用反射Api对某个类进行反射调用时
5. 当初次调用MethodHandle实例时,初始化该MethodHandle指向的方法所在的类;
第5点我也不太明白是啥意思~^_^
行了,就介绍到这吧!洗漱….睡觉…..
参考:
https://www.cnblogs.com/jimxz/p/3974939.html
)