一、分类:
1.BootStrap Class Loader:启动类加载器,负责加载rt.jar文件中所有的Java类,即Java的核心类都是由该ClassLoader加载。在Sun JDK中,这个类加载器是由C++实现的,并且在Java语言中无法获得它的引用。
2.Extension Class Loader:扩展类加载器,负责加载一些扩展功能的jar包。
3.System Class Loader:系统类加载器,负责加载启动参数中指定的Classpath中的jar包及目录,通常我们自己写的Java类也是由该ClassLoader加载。在Sun JDK中,系统类加载器的名字叫AppClassLoader。
4.User Defined Class Loader:用户自定义类加载器,由用户自定义类的加载规则,可以手动控制加载过程中的步骤。
二、工作原理:
类加载分为装载、链接、初始化三步。
1.装载
通过类的全限定名和ClassLoader加载类,主要是将指定的.class文件加载至JVM。当类被加载以后,在JVM内部就以“类的全限定名+ClassLoader实例ID”来标明类。
在内存中,ClassLoader实例和类的实例都位于堆中,它们的类信息都位于方法区。
装载过程采用了一种被称为“双亲委派模型(Parent Delegation Model)”的方式,当一个ClassLoader要加载类时,它会先请求它的双亲ClassLoader(其实这里只有两个ClassLoader,所以称为父ClassLoader可能更容易理解)加载类,而它的双亲ClassLoader会继续把加载请求提交再上一级的ClassLoader,直到启动类加载器。只有其双亲ClassLoader无法加载指定的类时,它才会自己加载类。
双亲委派模型是JVM的第一道安全防线,它保证了类的安全加载,这里同时依赖了类加载器隔离的原理:不同类加载器加载的类之间是无法直接交互的,即使是同一个类,被不同的ClassLoader加载,它们也无法感知到彼此的存在。这样即使有恶意的类冒充自己在核心包(例如java.lang)下,由于它无法被启动类加载器加载,也造成不了危害。
由此也可见,如果用户自定义了类加载器,那就必须自己保障类加载过程中的安全。
2.链接
链接的任务是把二进制的类型信息合并到JVM运行时状态中去。
链接分为以下三步:
a.验证:校验.class文件的正确性,确保该文件是符合规范定义的,并且适合当前JVM使用。
b.准备:为类分配内存,同时初始化类中的静态变量赋值为默认值。
c.解析(可选):主要是把类的常量池中的符号引用解析为直接引用,这一步可以在用到相应的引用时再解析。
3.初始化
初始化类中的静态变量,并执行类中的static代码、构造函数。
JVM规范严格定义了何时需要对类进行初始化:
a、通过new关键字、反射、clone、反序列化机制实例化对象时。
b、调用类的静态方法时。
c、使用类的静态字段或对其赋值时。
d、通过反射调用类的方法时。
e、初始化该类的子类时(初始化子类前其父类必须已经被初始化)。
f、JVM启动时被标记为启动类的类(简单理解为具有main方法的类)。