类加载系统
什么是类加载?
字节码存储在硬盘上,需要运行时,类加载系统负责将类的信息加载到内存中(方法区)为每个类创建一个class类的对象,使用的是ClassLoader进行加载,充当一个快递员的角色。ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。
类加载的角色
1.class file 存在于硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载JVM当中来,根据这个模板实例化出n个一模一样的实例。
2.class file加载到JVM中,被称为DNA元数据模板,放在方法区中。
3.在.class-->JVM-->最终称为元数据模板,此过程就要有一个运输工具(类加载器 Class Loader) ,扮演一个快递员的角色。
类加载过程
加载(Loading)-->验证(Verification)-->准备(Preparation)-->解析(Resolution)-->初始化(Initialization)
加载
将硬盘字节读入到内存中,生成此类的Class对象,把硬盘上的结构转为内存结构。
链接
验证:
1.验证字节格式,是否被修改(污染)。
2.验证语法,例如类是否继承final的类
准备:
在准备阶段负责为类的静态属性分配内存,为类中静态的变量赋予初始值;
不包含用final修饰的static常量,在编译时进行初始化。
例如:static int num = 123; -->在准备阶段static int num 的初始值时0,而不是123。
在准备阶段不为静态的常量进行赋值。
解析:
将符号引用(文件中的逻辑引用)转为直接引用(内存中的实际地址)。
初始化
对类中静态成员进行赋值
类什么时候初始化?
(1)创建类的实例,也就是new一个对象;
(2)访问某个类或接口的静态变量,或者对该静态变量赋值;
(3)调用类的静态方法;
(4)反射(Class.forName("")):
(5)初始化一个类的子类(会首先初始化子类的父类)。
类的初始化顺序
对static修饰的变量或语句块进行赋值。
如果同时包含多个静态变量和静态代码块,按照自上而下的顺序依次执行
类初始化顺序:父类static-->子类static-->父类构造方法-->子类构造方法
public class ClassInit {
static int num = 10; //准备阶段为静态的变量赋默认值 0 初始化阶段赋值10
static final int sum = 100;//static final 在编译期间赋值
static {
num = 20;
}
public static void main(String[] args) {
System.out.println(num);
}
}
类加载器分类
类加载器就是通过一个类的全限定名称来获取其二进制文件(即.class文件)并加载到JVM中的工具。
站在JVM的角度看,类加载器可以分为两种:
1.启动类加载器(引导类加载器),在部分不是用Java语言写的。
2.其他类加载器(这部分指的是用Java语言写的类加载器)。
站在Java开发人员的角度看:
1.启动类加载器,负责加载Java核心类;
2.扩展类加载器 负责加载\jre\lib\ext目录下的类,包含应用程序类加载器;
3.应用程序类加载器,负责加载自己写的程序中的类。
双亲委派机制
为了确保类加载的正确性、安全性,在加载类时,采用双亲委派机制,当需要加载程序中一个类时,会先让加载器的父级去加载,直到最顶级的启动类加载器,如果父级找到了返回使用,如果依然没有找到,那么就委派给子级去加载,找到了就返回,如果所有的类加载器都没有找到,报类找不到异常。
优点:
安全,避免了自己写的类替换了系统中的类;
避免类重复加载。
类的主动使用/被动使用
在JVM中规定,每个类或者接口被首次主动使用时才对其进行初始化,有主动使用,自然就有被动使用。
主动使用:
-通过new关键字被导致类的初始化,这是大家经常使用的初始化一个类的方式;
-访问类的静态变量,包括读取和更新;
-访问类的静态方法;
-对某个类进行反射操作,会导致类的初始化;
-初始化子类会导致父类的初始化;
-执行该类的main函数。
被动使用:
-引用该类的静态常量(注意是常量,不会导致初始化,但这里的常量是指已经指定字面量的常量,但是对于需要计算得出结果的常量会导致初始化)。
public final static int NUM = 5 ; //不会导致类初始化,被动使用
public final static int RAD = new Random().nextInt() ; //会导致类的初始化,主动使用
-创建数组,用类作为类型使用,不会导致该类的初始化。
User[] users= new User[10] ;
主动使用和被动使用的区别在于类是否会被初始化。