繁体   English   中英

什么是 Java 类加载器?

[英]What is a Java ClassLoader?

简单说几句,什么是Java ClassLoader,什么时候用,为什么用?

好的,我读了一篇维基文章。 ClassLoader 加载类。 好的。 因此,如果我包含 jar 文件并导入,则 ClassLoader 会完成这项工作。

为什么我要打扰这个类加载器? 我从未使用过它,也不知道它的存在。

问题是,ClassLoader 类为什么存在? 而且,您如何在实践中使用它? (案例存在,我知道。)

取自 Sun 的这个不错的教程

动机

以静态编译的编程语言(例如 C 和 C++)编写的应用程序被编译为本地机器特定指令并保存为可执行文件。 将代码组合成可执行本机代码的过程称为链接——将单独编译的代码与共享库代码合并以创建可执行应用程序。 这在动态编译的编程语言(如 Java)中有所不同。 在 Java 中,Java 编译器生成的 .class 文件在加载到 Java 虚拟机 (JVM) 之前保持原样——换句话说,链接过程由 JVM 在运行时执行。 类在“根据需要”的基础上加载到 JVM 中。 当一个加载的类依赖于另一个类时,那个类也会被加载。

当 Java 应用程序启动时,要运行的第一个类(或应用程序的入口点)是具有称为 main() 的 public static void 方法的类。 这个类通常有对其他类的引用,所有加载被引用类的尝试都由类加载器执行。

要大致了解这种递归类加载以及类加载思想,请考虑以下简单类:

public class HelloApp {
   public static void main(String argv[]) {
      System.out.println("Aloha! Hello and Bye");
   }
}

如果您指定 -verbose:class 命令行选项运行此类,以便打印正在加载的类,您将获得如下所示的输出。 请注意,这只是部分输出,因为列表太长而无法在此处显示。

prmpt>java -verbose:class HelloApp



[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]

如您所见,应用程序类(HelloApp)所需的 Java 运行时类首先被加载。

Java 2 平台中的类加载器

Java 编程语言不断发展,使应用程序开发人员的日常生活变得更加轻松。 这是通过提供 API 来实现的,这些 API 允许您专注于业务逻辑而不是基本机制的实现细节,从而简化您的生活。 最近为了反映 Java 平台的成熟度而将 J2SE 1.5 更改为 J2SE 5.0 就证明了这一点。

从 JDK 1.2 开始,JVM 内置的引导类加载器负责加载 Java 运行时的类。 该类加载器仅加载在引导类路径中找到的类,并且由于这些是受信任的类,因此不会像对不受信任的类那样执行验证过程。 除了引导类加载器之外,JVM 还具有一个扩展类加载器,负责从标准扩展 API 加载类,以及一个系统类加载器,它从通用类路径以及您的应用程序类加载类。

因为有多个类加载器,所以它们用一棵树表示,其根是引导类加载器。 每个类加载器都有一个对其父类加载器的引用。 当要求类加载器加载一个类时,它会在尝试加载项目本身之前咨询其父类加载器。 父级依次咨询其父级,依此类推。 所以只有在所有祖先类加载器都找不到当前类加载器涉及的类之后。 换句话说,使用了委托模型。

java.lang.ClassLoader 类

java.lang.ClassLoader是一个抽象类,需要扩展 JVM 动态加载类的方式的应用程序可以将其子类化。 java.lang.ClassLoader (及其子类)中的构造函数允许您在实例化新类加载器时指定父类。 如果您没有明确指定父级,虚拟机的系统类加载器将被分配为默认父级。 换句话说,ClassLoader 类使用委托模型来搜索类和资源。 因此,ClassLoader 的每个实例都有一个关联的父类加载器,因此当请求查找类或资源时,在尝试查找类或资源本身之前,将任务委托给其父类加载器。 ClassLoader 的loadClass()方法在调用加载类时按顺序执行以下任务:

如果一个类已经被加载,它会返回它。 否则,它将对新类的搜索委托给父类加载器。 如果父类加载器没有找到该类,则loadClass()调用findClass()方法来查找并加载该类。 如果父类加载器未找到该类,则finalClass()方法会在当前类加载器中搜索该类。


原始文章中有更多内容,它还向您展示了如何实现自己的网络类加载器,它回答了您关于为什么(以及如何)的问题。 另请参阅API 文档

大多数 Java 开发人员永远不需要显式使用类加载器(除了加载资源,以便在将它们捆绑在 JAR 中时它仍然可以工作),更不用说编写自己的类加载器了。

类加载器在大型系统和服务器应用程序中用于执行以下操作:

  • 模块化系统并在运行时加载、卸载和更新模块
  • 并行使用不同版本的 API 库(例如 XML 解析器)
  • 隔离在同一 JVM 中运行的不同应用程序(确保它们不会相互干扰,例如通过静态变量)

问题是“为什么要打扰这个 ClassLoader 类的存在”?

嗯,主要是这样你就可以在出错时解决问题:-)。

没错,只要您只是编写一个应用程序,将其编译为 JAR 并可能包含一些额外的库 JAR,您就不需要了解类加载器,它就可以工作。

尽管如此,了解一些类加载器和类加载的知识有助于更好地理解幕后发生的事情。 例如,“静态初始化程序”将在类加载时运行,因此要了解它们何时运行,您需要知道类加载器如何决定何时加载它们。

还有..你如何在实践中使用它?

对于简单的情况,您不需要它们。 但是,如果您需要在运行时动态加载代码并明确控制代码的来源(例如通过网络加载、加载编译时不可用的插件等),您可能需要做更多的事情。 然后你可以编写你自己的类加载器。 有关链接,请参阅其他答案。

Java中的ClassLoader是Java中用来加载类文件的类。 Java代码由javac编译器编译成class文件,JVM通过执行class文件中写入的字节码来执行Java程序。

ClassLoader 负责从文件系统、网络或任何其他来源加载类文件。 Java 中使用了三个默认的类加载器, BootstrapExtensionSystem or Application类加载器。

类加载器


类加载器的工作原理

## ClassLoader 与 JVM 的交互在此处输入图片说明

更多 @ : how-classloader-works-in-java.html

类加载器是 JVM 的一个功能组件,它将类数据从“.class”文件或通过网络加载到堆中的方法区。

看起来像是 JVM 的一个组成部分,但作为最终的 Java 用户,我为什么要担心呢? 原因如下:

每个类加载器都有自己的命名空间,由特定类加载器调用的类进入它的命名空间。

由两个不同的类加载器调用的类将不会相互可见,从而增强了安全性。

类加载器父子委托机制确保 java api 类永远不会被未经授权的代码破解。

详情请看这里

类加载器是分层的。 类被引入 JVM,因为它们在 JVM 中已运行的类中按名称引用。

头等舱怎么装?
第一个类是在类中声明的static main()方法的帮助下加载的。 所有随后加载的类都由已经加载并运行的类加载。

类加载器创建一个命名空间。 所有JVM 都包含至少一个嵌入在 JVM 中的类加载器,称为原始(或引导)类加载器。 这是一回事,我们将研究非原始类加载器。 JVM 中有钩子,允许使用用户定义的类加载器代替原始类加载器。 下面是 JVM 创建的类加载器。

Bootstrap (primordial)此类加载器不可重新加载。 加载 JDK 内部类、java.* 包(通常加载 rt.jar 和 i18n.jar)。 Extesions 这个类加载器不可重新加载。 从 JDK 扩展目录(通常是 JRE 的 lib/ext)加载 jar 文件。 System 此类加载器不可重新加载。 从系统类路径加载类。

http://www.sbalasani.com/2015/01/java-class-loaders.html

当你问为什么 ClassLoader 类存在时,原因很简单——它是负责在运行时查找和加载类文件的类

让我们详细说明一下。

在 JVM 中,每个类都由java.lang.ClassLoader的某个实例加载。 每当一个新的 JVM 由您通常的 Java 程序启动java <classname>命令时,第一步是将所有关键类加载到内存中以便正常工作所需的所有关键类,如java.lang.Object和其他运行时类 ( rt.jar )。

现在,ClassLoader 实际上有 3 个部分:

  • BootstrapClassLoader负责使这些类可用,即将这些类加载到内存中。

  • 下一个任务是将任何外部库/JAR 加载到内存中,以便应用程序正常工作。 ExtClassLoader负责这个任务。 这个类加载器负责加载 java.ext.dirs 路径中提到的所有 .jar 文件。

  • 第三个也是主要的重要类加载器是AppClassLoader 应用程序类加载器负责加载 java.class.path 系统属性中提到的类文件。

同样重要的是要注意,默认的 ClassLoader 实现可以被覆盖,使您能够以有用和有趣的方式自定义 JVM,允许您完全重新定义类文件被引入系统的方式。

在此处输入图片说明

查看它以了解有关Java 类加载器的更多信息。

类加载器

ClassLoader是 Java 运行时环境 (JRE) 的一部分,它动态地将类(环境对象 - java.lang.Class和文件.class )加载到 JVM(Java 虚拟机)中。 JRE 使用延迟类加载(按需)它可以减少内存占用。 当应用程序需要某个类 JRE 要求 ClassLoader 加载这个类

有一个 ClassLoader 类的层次结构

  • BootStrap 或 Primodial - root 并且是内置的(getClassLoader() 时返回 null)JDK 类。 从 rt.jar 加载类
  • Extension(Platform Java v9) - 核心 Java 类。 从 jre/lib/ext 目录加载类或由 java.ext.dirs 系统属性指向
  • 系统/应用程序 - 来自classpath [关于]或命令行选项(-cp,-classpath)的应用程序类

您还可以为您的特定情况创建自己的 ClassLoader 类。 例如从某个存储库加载类,使用版本控制、卸载、安全

要检查谁确切地加载了您的课程,请使用getClassLoader()

SomeClass.class.getClassLoader()

查找类流(委托模型)

child classloader find in cache 
    if not 
        parent classloader find in cache 
            if not
        parent classloader try to load
    if not
child classloader try to load

[ClassNotFoundException vs NoClassDefFoundError 和隐式 vs 显式类加载]

[iOS 动态链接器]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM