类加载运行全过程
一.类加载过程
加载文件>验证格式>准备赋默认值>解析符号引用>初始化代码
1.加载
在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为 方法区 这个类的各种数据的访问入口
简述:
在类被使用到的时候,将class文件加载到内存的方法区中.
2. 验证
验证加载的字节码文件正确性
3. 准备
给类的静态变量分配内存,并赋予默认值
4. 解析
将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如 main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过 程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用
简述:
将符号替换为指针,指向对应的内存(eg. main()方法里面的代码 会在方法区生成,解析会将符号转成对应的代码的内存地址,要使用到该方法时,直接通过内存地址找到并执行)
5. 初始化
对类的静态变量初始化为我们指定的值,并执行静态代码块
二.类加载到方法区中生成了那些东西?
- 运行时常量池
- 类型信息
- 字段信息
- 方法信息
- 类加载器的引用
- 对应class实例的引用
类加载器在加载类信息放到方法区后,
会创建一个对应的Class类型的对象实例放到堆(Heap)中,
作为开发人员访问方法区中类定义的入口和切入点 - 其它
注意:
主类如果使用到其它类,会逐步加载这些类
jar包或war包里的类不是一次性全部加载的,是使用到才会加载.
三.类加载器和双亲委派机制
1.什么是类加载器?
类加载器也是一个类,只是它实现了这个功能,用于加载类
2.有几种类加载器?
上面的类加载过程主要是通过类加载器来实现,Java由如下几种类加载器
- 引导类加载器
负责加载支撑JVM运行的位于JRE的lib目录下的核心类库 - 扩展类加载器
负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包 - 应用程序类加载器
负责加载ClassPath路径下的类包,主要是加载自己写的类 - 自定义加载器
加载用户自定义路径下的类包
3.类加载器初始化过程
参见类运行加载全过程图可知
其会创建JVM启动器实例sun.misc.Launcher(以下简称LC).
LC 也是一个JAVA类,只不过它是直接由Java虚拟机(内部代码由C++实现)直接创建的
LC使用了单例模式设计,保证了一个JVM虚拟机内只有一个LC实例(JVM虚拟机可以有多个,一个进程对应一个)
在Launcher构造方法内部,其创建了两个类加载器分别是
sun.misc.Launcher.ExtClassLoader(扩展类加载器)
和
sun.misc.Launcher.AppClassLoader(应用类加载器)。
四.双亲委派机制
1.什么是双亲委派机制?
- 做了什么:
加载某个类时,会委托父加载器寻找目标类,找不到再委托更上层的父加载器加载,如果所有父加载器都找不到,则在自己加载
简述:加载类时优先父加载器加载
2.为什么要设计双亲委派机制?
- 沙箱安全机制:保证核心Api库不会被篡改
- 避免重复加载类:父加载加载过的,没必要再加载一次,保证被加载类的唯一性
五.全盘负责委托机制
“全盘负责”是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类 所依赖及引用的类也由这个ClassLoder载入。
六.自定义类加载器:
继承 java.lang.ClassLoader 类,,该类有两个核心方法,一个是 loadClass(String, boolean),实现了双亲委派机制,还有一个方法是findClass,默认实现是空方法,所以我们自定义类加载器主要是重写findClass方法。