接下来介绍下JAVA中非常重要的一个类ClassLoader(类装载器)

类装载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件。主要工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class字节码文件。
在JAVA中java虚拟机把一个类装入到java虚拟机当中需要经过以下的步骤:
1.装载:查找和导入Class文件
2.链接:执行校验,准备和解析步骤。
其中校验主要是检查载入class文件数据的正确性,而准备工作就是给类的静态变量来分配存储空间,解析则是将符号引用来转变成直接引用。
3.初始化:对类的静态变量、静态代码块执行初始化工作
类文件被装载并解析之后,在java虚拟机内将拥有一个对应的java.lang.class类描述对象。该类的对象实例则拥有指向这个类描述对象的引用。而类描述对象又拥有指向关联ClassLoader的引用。
每一个类在java虚拟机当中都拥有一个对应的java.lang.class文件。他提供了类结构信息的描述,数组、枚举、注解以及基本的java类型,甚至void都拥有对应的class属性。Class没有public的构造方法,class是在装载类时由java虚拟机调用类装载器中的defineClass方法来自动构造的。
JVM装载类时使用 全盘负责委托机制
全盘负责:当一个ClassLoader装载一个类的时候,除非显式的使用另一个ClassLoader,否则该类所依赖即引用的类也由这个ClassLoader来载入。
委托机制:先委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全角度来考虑的。
JVM在运行时会产生三个字节码文件:根装载器ExtClassLoader( 扩展类装载器 AppClassLoader( 系统类装载器
根装载器:不是ClassLoader的子类,由于他是使用C++来编写的,因此在JAVA中看不到他。根装载器来复制装载jre的核心类库,如jre目标下的rt.jar、charsets.jar等。
ExtClassLoader:是ClassLoader的子类,负责装载jre扩展目录ext中的jar类包
AppClassLoader:是ClassLoader的子类,负责装载classpath路径下的类
这三个装载器之间存在着父子层级的关系:
根装载器是ExtClassLoader的父装载器,而ExtClassLoader是AppClassLoader的父装载器。
在默认情况下使用AppClassLoader装载应用程序的类。
接下来我们在程序中来验证一下
public class ClassLoaderTest {

  public static void main(String[] args) {
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      System.out.println("current loader:"+loader);//打印当前类装载器的信息
      System.out.println("parent loader:"+loader.getParent());//打印当前类装载器的父类
      System.out.println("grandparent loader:"+loader.getParent().getParent());//打印当前类装载器的祖父
      //注意:根装载器在JAVA中访问不到
  }
}
可以看到打印的结果
current loader:sun.misc.Launcher$AppClassLoader@4b67cf4d
parent loader:sun.misc.Launcher$ExtClassLoader@60e53b93
grandparent loader:null

在JAVA中ClassLoader是一个抽象类,主要位于java.lang包中。接下来主要介绍一下该类主要的接口方法。
1.    Class loadClass(String name)
其中name参数是指定类装载器需要装载类的名字,且必须使用全限定类名。
在初始化类之前,应考虑进行类解析的工作,但并不是所有的类都需要解析。
如果java虚拟机只需要知道该类是否存在或者找该该类的超类那么就不需要进行解析。
2.    Class defineClass(String name, byte[]b, int off,int len)
这个方法是将类文件的字节数组来转换为java虚拟机内部的java.lang.class对象。字节数组可已从本地文件系统,远程网站中进行获取。而name为字节数组对应的全限定名。
3.    Class findSystemClass(String name)
从本地文件系统来载入class文件,如果本地文件系统不存在该class文件,那么他将会抛出ClassNotFoundException这个异常。这个方法是java虚拟机默认使用的机制。
4.    Class findLoadedClass(String name)
调用该方法来查看classloader是否以装入到某个类当中,如果已经装入则返回java.lang.class对象,否则返回null。
如果强行装载已经存在的类,那么将会抛出链接错误。
5.    ClassLoader getParent()
获取类装载器的父装载器。除根装载器之外,所有的类装载器都有且仅有一个父装载器。ExtClassLoader的父装载器是根装载器,因为根装载器非java编写,所以返回null。
除了java虚拟机默认的三个装载器之外,还允许自定义装载器用来实现一些特殊的需求。


Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐