Java 类加载机制详细介绍

论坛 期权论坛 脚本     
niminba   2021-5-23 02:55   1070   0

一、类加载器

  类加载器(ClassLoader),顾名思义,即加载类的东西。在我们使用一个类之前,JVM需要先将该类的字节码文件(.class文件)从磁盘、网络或其他来源加载到内存中,并对字节码进行解析生成对应的Class对象,这就是类加载器的功能。我们可以利用类加载器,实现类的动态加载。

二、类的加载机制

  在Java中,采用双亲委派机制来实现类的加载。那什么是双亲委派机制?在Java Doc中有这样一段描述:

The ClassLoader class uses a delegation model to search for classes and resources. Each instance
 of ClassLoader has an associated parent class loader. When requested to find a class or resource,
 a ClassLoader instance will delegate the search for the class or resource to its parent class loader
 before attempting to find the class or resource itself. The virtual machine's built-in class loader,
 called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a
 ClassLoader instance.

 从以上描述中,我们可以总结出如下四点:

1、类的加载过程采用委托模式实现

2、每个 ClassLoader 都有一个父加载器。

3、类加载器在加载类之前会先递归的去尝试使用父加载器加载。

4、虚拟机有一个内建的启动类加载器(bootstrap ClassLoader),该加载器没有父加载器,但是可以作为其他加载器的父加载器。

   Java 提供三种类型的系统类加载器。第一种是启动类加载器,由C++语言实现,属于JVM的一部分,其作用是加载 <Java_Runtime_Home>/lib 目录中的文件,并且该类加载器只加载特定名称的文件(如 rt.jar),而不是该目录下所有的文件。另外两种是 Java 语言自身实现的类加载器,包括扩展类加载器(ExtClassLoader)和应用类加载器(AppClassLoader),扩展类加载器负责加载<Java_Runtime_Home>\lib\ext目录中或系统变量 java.ext.dirs 所指定的目录中的文件。应用程序类加载器负责加载用户类路径中的文件。用户可以直接使用扩展类加载器或系统类加载器来加载自己的类,但是用户无法直接使用启动类加载器,除了这两种类加载器以外,用户也可以自定义类加载器,加载流程如下图所示:

  注意:这里父类加载器并不是通过继承关系来实现的,而是采用组合实现的。

  我们可以通过一段程序来验证这个过程:

public class Test {
}
 
public class TestMain {
  public static void main(String[] args) {
 
    ClassLoader loader = Test.class.getClassLoader();
    while (loader!=null){
      System.out.println(loader);
      loader = loader.getParent();
    }
  }
}

  上面程序的运行结果如下所示:  

  从结果我们可以看出,默认情况下,用户自定义的类使用 AppClassLoader 加载,AppClassLoader 的父加载器为 ExtClassLoader,但是 ExtClassLoader 的父加载器却显示为空,这是什么原因呢?究其缘由,启动类加载器属于 JVM 的一部分,它不是由 Java 语言实现的,在 Java 中无法直接引用,所以才返回空。但如果是这样,该怎么实现 ExtClassLoader 与 启动类加载器之间双亲委派机制?我们可以参考一下源码:

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
  {
    synchronized (getClassLoadingLock(name)) {
      // First, check if the class has already been loaded
      Class<?> c = findLoadedClass(name);
      if (c == null) {
        long t0 = System.nanoTime();
        try {
          if (parent != null) {
            c = parent.loadClass(name, false);
          } else {
            c = findBootstrapClassOrNull(name);
          }
        } catch (ClassNotFoundException e) {
          // ClassNotFoundException thrown if class not found
          // from the non-null parent class loader
        }
 
        if (c == null) {
          // If still not found, then invoke findClass in order
          // to find the class.
          long t1 = System.nanoTime();
          c = findClass(name);
 
          // this is the defining class loader; record the stats
          sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
          sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
          sun.misc.PerfCounter.getFindClasses().increment();
        }
      }
      if (resolve) {
        resolveClass(c);
      }
      return c;
    }
  }

  从源码可以看出,ExtClassLoader 和 AppClassLoam的技术都已不遵循这一规则,如 OSGi 技术就采用了一种网状的结构,而非双亲委派机制。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP