jvm的类加载器,类装载过程
Posted yangfeiorfeiyang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jvm的类加载器,类装载过程相关的知识,希望对你有一定的参考价值。
混沌初开,在一片名为jvm的世界中,到处都是一片虚无,直到一个名为BootstrapClassLoader的巨人劈开了世界,据说它是由名叫C++的女神所造,它从一个叫做jre/lib的宝袋中拿出一把开天之斧ExtensionClassLoader,以及其他各种各样五颜六色的宝物,这些宝物撒落在混沌世界中,
化作了山山水水.紧接着,巨人又使用ExtensionClassLoader这把巨斧劈开了一个叫做jre/lib/ext的巨峰,那里瞬间迸发出了五颜六色的彩芒,彩芒四溅而去,让这个灰色的世界不再那么暗淡.紧接着,名为BootStrapClassloader的巨人又将ExtensionClassLoader变成了一把宝剑,这把宝剑
名为ApplicationClassloader(其父类是ExtensionClassLoader),它光芒四射,巨人将它放入了一个名为环境变量的水池中,那里有一个身上刻着CLASSPATH的金鱼,巨人用宝剑插到了金鱼的身上,金鱼的血在宝剑上流动着,最后形成了串字符 D://myJavaClass/.之后宝剑爆发出了万丈光芒,这些光芒映照在天空之上,形成了以下
这些字:
一个类的加载过程分为:加载,验证,准备,解析,初始化
加载:顾名思义,就是根据类的全路径将类文件以二进制流的形式加载到内存中,当然,除了本地加载之外,jvm也支持从网络远程加载(需要自己实现类加载器)以及运行时动态生成(典型例子:动态代理),加载阶段,其实是我们自定义类加载器时最好控制的阶段,因为我们可以在findClass()方法里拿到class文件的二进制流后,自定义业务逻辑
之后将二进制流传入defineClass()方法.
验证:查看class文件数据是否符合规范以及是否会对jvm造成影响如:该类是否继承了被final修饰的类,类型转换是否正常(如:一个int不能强转为String),对于其他类属性的访问是否有权限(private,public)
准备:为内存中的静态成员变量分配空间,并赋默认值,但如果是被final 修饰的静态成员变量且其是基本数据类型或者字符串类型.也就给其赋值,并将其值存入静态常量池中.(前提条件是有静态且被final修饰的成员变量,并且它的赋值是基本数据类型或者字符串)
解析:将类成员变量和方法的字面量转换为直接引用也就是内存地址的过程(字面量是什么意思呢?好比你有个helloWorld()方法,此时这个方法的字面量就是helloWorld,如果是int a = 0,那么0就是字面量,记住,是字面量,但它不是具体值,因为值其实是一个内存地址),解析阶段不是必需的,如果你的类里没有静态成员变量或者方法就不会进行
初始化:在这个阶段,静态成员变量会被赋上我们开发人员定义的值,而此时如果有静态成员变量引用的是其它类的成员变量,或者是方法,或者直接就是new了,那么此时会去初始化其它类,而如果其它类里有反引用了本类,并且是静态成员变量,那么会直接调用本类的
构造方法,对本类进行初始化,再回到其它类.当然,这一切的前提是,如果此类有父类的话,那么必先初始化其父类.
其实初始化并非是一定触发的,但有3种必定会触发初始化
1:使用new关键字
2:通过反射机制也就是newInstance(),这里再拓展一点反射获取Class对象的知识1:getClass()此方法是通过对象头里的Class指针拿到的对应此对象的Class对象,此方法不会触发初始化,因为你都拿到对象了啊,已经初始化过了.2:类名.class,不会触发初始化机制,因为在编译阶段的时候class引用就被添加到静态常量池里了.3:Class.forName(),会触发静态代码块,因为这个方法会将类装载到内存中,并且初始化.
3:执行main方法的类
还有几种不会触发,1:我之前说的被final修饰的静态成员变量,并且值是字符串或者基本数据类型
2:子类通过父类直接拿父类的静态成员变量,不会触发子类的初始化,会触发父类的初始化,哪怕是被final修饰的静态成员变量,不过请注意的是,子类会被装载到内存中的.
3:被数组定义的类,如:Student[] stuArr = new Student[2];
最后,拓展一个知识点,JAVA还有一个线程加载器,可以实现单个线程内加载类.也就是不同的线程可以加载相同的类
以上是关于jvm的类加载器,类装载过程的主要内容,如果未能解决你的问题,请参考以下文章