Java ClassLoader深入解析(一)

    xiaoxiao2025-01-26  2

    一、类加载器原理简介

    Java 编译器会为虚拟机转化源指令。虚拟机代码存储在以.class为扩展名的类文件中,每个类文件都包含某个类

    或者接口的定义和代码实现。这些类文件必须由一个程序进行解释,该程序能够将虚拟机的指令集翻译成目标机器的机器语言。

    请注意,虚拟机只加载程序执行时所需要的类文件。例如,假设程序从MyProgram.class开始运行,下面是虚拟

    机执行的步骤。

    (1)虚拟机有一个用于加载类文件的机制,例如,从磁盘上读取文件或者请求web上的文件;它使用该机制

    来加载MyProgram类文件中的内容。

    (2)如果MyProgram类拥有类型为另一个类的域,或者是拥有超类,那么这些类文件也会被加载

    (3)接着,虚拟机执行MyProgram中的main方法(它是静态的,无需创建类的实例)

    (4)如果main方法或者main调用的方法要用到更多的类,那么接下来就会加载这些类。然而,类加载机制并

    非只使用单个的类加载器。每个Java程序至少拥有三个类记载器。

     -引导类加载器

     -扩展类加载器

     -系统类加载器(有时也称为应用类加载器)

    引导类加载器负责加载类(通常从Jar文件rt.jar中进行加载)。它是虚拟机不可分割的一部分,而且通常是用

    C语言来实现的。引导类加载器没有对应的ClassLoader对象,如果,该方法: String.class.getClassLoader();将返回null.

    扩展类加载器用于jre/lib/ext目录加载“标准的扩展”。可以将JAR文件放入该目录,这样即使没有任何类路

    径,扩展类加载器也可以找到其中的各个类。

    系统类加载器用于加载应用类。它在有CLASSPATH环境变量或者-classpath命令行选项设置类路径的目录

    或者是JAR/ZIP文件里查找这些类。 在Oracle的Java语言实现中,扩展类加载器和系统类加载器都是用Java来实现的。它们都是URLClassLoader类的实例。

    二、类加载器的层次结构

    类加载器有一种父/子关系。除了引导类加载器外,每个类加载器都有一个父类加载器。根据规定,类加载器

    会为它的父类加载器提供一个机会,以便加载任何给定的类,并且只有在其父类加载失败时,它才会加载该给该给定类。例如,当要求系统加载器加载一个系统类(比如,java.util.ArrayList)时,它首先要求扩展类加载器进行加载,该扩展类加载器则首先要求引导加载器进行加载。引导类查找并加载rt.jar中的这个类,而无须其他类加载做更多的搜索。

    加载方式1:

    URL url=new URL("file:///path/to/plugin.jar"); URLClassLoader pluginLoader=new URLClassLoader(new URL[]{url}); Class<?> cl=pluginLoader.loadClass("mypackage.class"); 因为在URLClassLoader构造器中没有指定类加载器,因此pluginLoader的父亲就是系统类加载器.

    加载方式2:

    Class.forName(class-NameString);

    三、上下文类加载器

         每个线程都有一个对类加载器的引用,称为上下文加载器。主线程的上下文类加载器是系统类加载器。当新线程创建时,它的上下文加载器会被设置创建该线程的上下文类加载器。因此,如果你不做任何特殊的操作,那么所有线程就将它们的上下文加载器设置为系统类加载器。

    但是,我们也可以通过下面的调用将其设置为任何类的加载器

    Thread t=Thread.currentThread(); t.setContextClassLoader(loader);     然后助手方法可以获取这个上下文类加载器:

    Thread t=Thread.currentThread(); ClassLoader loader=t.getContextClassLoader(); Class cl=loader.loadClass(className);

    四、将类加载器作为命令空间

    每个Java程序员都知道,包的命名是为了消除名字冲突。在标准类库中,有两个名字为java.util.Date和java.sql.Date.

    使用简单的名字只是为了方便程序员,它们要求程序包含恰当的import语句。在一个正在执行的程序中,所有的类名都包

    括它的包名。

    然而,令人惊奇的是,在同一个虚拟机中,可以有两个类,它们的类名和包名是相同的。类是由它的全名和类加载器

    确定的。这项技术在加载来自多处的代码时很有用。例如,浏览器为每一个web页面都使用了一个独立的applet类加载器的

    实例。这样,虚拟机就可以区分来自不同web页的各个类,而不用管它们的名字是什么。

    如何编写自己的类加载器 正在编写中。。。

    转载请注明原文地址: https://ju.6miu.com/read-1295798.html
    最新回复(0)