JVM类加载器子系统ClassLoader

Posted 益达学长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM类加载器子系统ClassLoader相关的知识,希望对你有一定的参考价值。

1 类加载器与类的加载过程

类加载器子系统的作用:类加载子系统负责从文件或者网络中加载class文件,class文件在文件头有特定的文件标识。

类的加载过程:

加载:

1)通过一个类的全限定名获取定义此类的二进制字节流

2)将这个字节流所表示的静态存储结构转化为方法区的运行时数据结构

3)在内存中生成一个代表这个java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

链接:

1)验证:目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机的自身安全。

主要包括:文件格式验证,元数据验证,字节码验证,符号引用验证。

2)准备:为类变量分配内存空间,并赋初始默认值。这里不包括final修饰的static,因为final修饰的在编译时就会分配了,准备阶段会显式初始化。虚方法表也在此阶段创建并开始初始化,类的变量初始值准备完成后,jvm会把类的方法表也初始化完毕。

非前向引用:静态代码块可以给定义在静态代码块后的静态变量赋值,但是不能调用。

3)解析:将常量池内的符号引用转坏为直接引用的过程。

初始化:

初始化阶段就是执行类构造器()的过程,此方法不需要定义,是javac编辑器自动手机所有类变量的赋值动作和静态代码块中的语句合并而来。()不同于类的构造器,如果具有父类,jvm会保证子类的()执行前,父类的()已经执行完毕。

2 类加载器分类

jvm支持两周类加载器,分别为引导类加载器(Bootstrap ClassLader,和自定义加载器(User-Definedd ClassLoader).自定义加载器不仅是指开发人员自己定义的类加载器,而是将所有派生类生于抽象类ClassLoader的类加载器都划分为自定义类加载器。

常用的三个类加载器:

1)启动类加载器(引导类加载器,Bootstrap ClassLoader)

这个类加载器使用C/C++语言实现,嵌套在jvm内部,用于记载java核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供jvm自身需要的类。

并不继承java.lang.ClassLoader,没有父加载器。

出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类。

2)扩展类加载器(Extension ClassLoader)

由java语言编写,派生自ClassLoader类,父类加载器为启动类加载器。从java.ext.dirs系统属性所指定的目录中加载类库,或从jdk安装目录的jre/lib/ext子目录(扩展目录)下安装类库。如果用户创建的jar在此目录下,也会自动由扩展类加载器加载。

3)应用程序类加载器(AppClassLoader)

java语言编写,派生于ClassLoader类,父类加载器为扩展类加载器,负责加载环境变量classpath或系统属性java.class.path指定下的类库。此类加载器是程序中默认的加载器,一般来说,java应用的类都是由它来完成的。

3 ClassLoader的使用说明

ClassLoader类是一个抽象类,除了引导类加载器外斗继承自ClassLoader。

sun.mis.Laucher是一个虚拟机的入口应用,扩展类加载器和应用程序类加载器都是都是其定义的内部类。

获取ClassLoaderd的途径:

如果是String等java核心类库,由引导类加载器加载,因为是由c/c++编写,所以获取不到相应的对象,获取为null。

1)获取当前类的classloader :clazz.getClassLoader()

2)获取当前线程上下文的ClassLoader:Thread.currentThread().getContextClassLoader()

3)获取系统的ClassLoader:CladdLoader.getSystemClassLoader()

4)获取调用者的ClassLoaderL:DriverManager.getCallerClassLoader()

4 双亲委派机制

工作原理:如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类加载器去执行,直到向上委托至最顶层的启动类加载器。如果父类能够完成类加载任务,就成功返回,如果不能,子加载器才会尝试自己去加载。

优势:避免类的重复加载。保护程序安全,防止API被随意篡改。

沙箱安全机制:

自定义String类,但是在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件,报错信息说没有main方法就是因为加载的是rt.jar中的string类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制。

其他:

1)在jvm中表示两个class对象是否为同一个类存在的两个必要条件:类加载的完整类名必须一致,包括包名,加载这个类的列加载器必须相同。

2)jvm必须知道一个类型是由启动类加载器还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么jvm会将这个类加载器的一个引用作为类型信息的一部分保存在方法去中,当解析一个类型到另外一个类型的引用的时候,jvm需要保证这两个类的类记载器是相同的。

3)类的被动使用不会导致类的初始化

以上是关于JVM类加载器子系统ClassLoader的主要内容,如果未能解决你的问题,请参考以下文章

我的面试经之JVM类加载器子系统ClassLoader类的加载过程

关于类加载器(ClassLoader)

JVM进阶之类加载器详解

JVM进阶之类加载器详解

JVM之类加载classLoader

深入理解JVM中的ClassLoader类加载器