类加载机制就是指虚拟机将类的数据从class文件加载到内存中,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
生命周期:类从加载到内存到卸载出内存经历了四个阶段。加载、连接、初始化,使用。其中连接又分为三步骤:验证,准备,解析三个步骤。
类加载的时机:1、遇到new、putstatic、invokestatic等字节码指令。eg:new一个对象;set/get类中的静态字段;调用类中静态方法。
2、在使用反射机制的时候、
3、初始化类时,若有 没有初始化的父类。
一、加载
分为以下几步: 1、通过类的全限定名称获得该类的二进制字节流
2、将此字节流所代表的静态存储结构保存在方法区。
3、再内存中生成能代表这个类的class对象,作为访问方法区该类各种数据的入口。
类加载器:主要分为三类加载器。
1、启动类加载器:主要加载的是JVM自身需要的类。+lib/核心类库 以java、javax、sun开头的类
2、扩展类加载器:加载lib/ext目录下的类
3、系统类加载器:加载classpath下的类
双亲委派模式的优势:1、Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次
2、防止核心API库被随意篡改。当通过网络传递一个启动类已经加载过的类时,并不会根据网络发来的类信息去加载,而是返回自己已经加载过的该类。
二、连接:
加载阶段和连接阶段(Linking)的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始
1、验证:确保class文件中包含的字节流中包含的信息符合当前虚拟机的要求。
a、文件格式验证:是否以规定的魔数开头,以此判断该文件能否在当前虚拟机的处理范围之内;当前文件中各部分是否有被删除或附加的信息。
b、元数据验证:站在类的角度检测。是否有父类;是否继承了不允许继承的类;是否实现父类要求实现的方法;类中字段、方法是否与父类产生矛盾
c、字节码验证:进入类的内部去检测。成员定义的数据类型是否与实际使用时的类型相等。(父类赋值子类、子类赋值父类)
d、符号引用验证:将符号引用转化为直接引用。类的全限定命字符串是否能找到对应的类;是否能找到制定类的制定方法;是否有访问资源的权限。
2、准备:为类或接口的静态字段分配空间并为他们默认初始化。
public static int value = 123; 此时只是赋值为0;
public static final int value = 123; 此时会赋值为123
3、解析:将常量池中的符号引用替换成直接引用:
CONSTANT_CLASS_INFO =3;
三、初始化
执行<clinit>方法的过程。
<clinit>方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的与聚合成的。(父类的静态块优于子类)
<clinit>是用于初始化静态的类变量,<init>是初始化实例变量