一.什么时候加载
1.new一个对象,一个类的静态函数或者字段被调用
2.反射调用
3.当一个类的子类被加载,其父类首先会被加载
4.一个类的main 函数被调用
5.数组对象特殊,由虚拟机加载,不用类加载器加载
二.加载过程
主要过程: 1加载 2.链接(验证,准备,解析)3.初始化 4.使用 5 卸载
1、加载:将二进制的字节码加载到方法区,能够直接使用,
每个类只能被加载一次,每个线程都会有一个加载状态记录,方法区也有,
会在方法区中生成一个对应的class 对象,将静态资源加载到常量池,而常量会放在堆中。
2、验证:对字节码信息进行验证,
主要包括:方法访问信息,字节码是否合法,父类的函数接口是否被重写,能否被重写,
包括对于文件格式的验证,比如常量中是否有不被支持的常量?文件中是否有不规范的或者附加的其他信息?
对于元数据的验证,比如该类是否继承了被final修饰的类?类中的字段,方法是否与父类冲突?是否出现了不合理的重载?
对于字节码的验证,保证程序语义的合理性,比如要保证类型转换的合理性。
对于符号引用的验证,比如校验符号引用中通过全限定名是否能够找到对应的类?校验符号引用中的访问性(private,public等)是否可被当前类访问?
3、准备:为变量在方法区中分配内存,附初始值,final变量直接赋实际值;
4、解析: 将字符引用转化成实际引用,可以直接找到对应的地址。
符号引用。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。
直接引用。可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量
5.初始化。只对static的变量进行初始化,按照代码中自上而下的顺序进行。
三、类加载器
bootstracpClassLoader ------》ExtensionClassLoader ----------》ApplicztionClassLoader-----》自定义的类加载器;;;
类加载器并不是继承关系,而是逻辑上的继承;其中bootstracpClassLoader 是在虚拟机中,用C写的,剩下的是用Java写的。
判断两个类是否相等,必须类加载器相等,类也相等。
双亲委派模型,从下到上去找,如果父加载器能加载,用父加载器加载,为了保证一个类在虚拟机中是惟一的。
loadClass调用defineClass,自定义的类加载器重写defineClass,模板方法
网友评论