Java类加载器是用来在运行时加载类(*.class文件)。Java类加载器基于三个原则:委托、可见性、唯一性。委托原则把加载类的请求转发给父 类加载器,而且仅加载类当父 类加载器无法找到或者不能加载类时。可见性原则允许子类加载器查看由父类加载器加载的所有的类,但是父类加载器不能查看由子类加载器加载的类。唯一性原则 只允许加载一次类文件,这基本上是通过委托原则来实现的并确保子类加载器不重新加载由父类加载器加载过的类。正确的理解类加载器原理必须解决像 NoClassDefFoundError in Java、 java.lang.ClassNotFoundException(这些现象和加载类有关系)的问题。类加载器在高级Java面试中也是一个重要的课 题,在此场合中对类加载器和类路径的工作原理有一定的了解是Java程序员所预期的。我在各种Java面试中经常遇见这样的问题:在Java中一个类可以 被两个不同的类加载器加载吗?在本文中,我们将学习什么是Java中的类加载器、它的工作原理以及与它有关的一些细节。
Java的类加载器是什么
Java 中的类加载器是加载Java类文件(*.class)的一个类。Java代码被javac 编译器编译后以字节码的形式保存到类文件,JVM(Java虚拟机)通过操作类文件里的字节码来执行Java程序。类加载器负责从文件系统、网络或任何其 它资源中加载类文件。Java中使用的默认类加载器有以下三种:Bootstrap , Extension以及System or Application class loader。每个类加载器都有一个预定义的位置,它们在那里加载类文件。Bootstrap 类加载器负责从rt.jar中加载标准JDK类文件,并且它是Java中所有类加载器的父级。Bootstrap类加载器没有任何父级,如果你调用String.class.getClassLoader() 则返回null 而且与此相关的代码则抛出空指针异常。Bootstrap类加载器在java中也被称为Primordial ClassLoader(原生类加载器) 。Extension类加载器委托它的父级Bootstrap类加载器来加载类文件,如果委托失败,则从指向java.ext.dirs 系统属性的jre/lib/ext目录或者任何其它目录加载类文件。JVM中的Extension类加载器被sun.misc.Launcher$ExtClassLoader实现。JVM 使用的第三种默认类加载器就是System or Applicationclass loader,它主要负责从CLASSPATH环境变量中加载应用程序特定的类文件,-classpath or -cp 命令行选项, JAR内部清单文件的类路径属性。Application类加载器是Extension类加载器的子级,它由sun.misc.Launcher$AppClassLoader类实现。而且,除Bootstrap 类加载器(大都由C 语言实现)以外,所有的Java类加载器使用java.lang.ClassLoader 来实现。
简而言之,这三种类加载器加载类文件的路径如下:
1) Bootstrap ClassLoader - JRE/lib/rt.jar
2) Extension ClassLoader - JRE/lib/ext 或者任何指向java.ext.dirs的路径
3) Application ClassLoader - CLASSPATH环境变量、-classpath or -cp 命令行选项,
JAR内部清单文件的类路径属性
Java类加载器工作原理
正如我前面所描述的那样,java类加载器基于三个原则:委托、可见性、唯一性。在本节中我们将看到这些原则的细节之处以及通过示例来理解java类加载器工作原理。顺便说一句,这里有一个关系图,它解释了在java中通过使用委托类加载器如何加载类文件。
委托原则
在探讨java中的类文件在什么时候被加载和初始化的问题时,java中的类文件在它被需要的时候被加载。假设您有一个叫做Abc.class 的应用程序特定的类文件,加载这个类文件的第一个请求发送到 Application类加载器。Application类加载器委托它的父级Extension类加载器,而Extension类加载器委托给Bootstrap类加载器。Bootstrap类加载器在rt.jar 中寻找类文件,由于没有找到,请求转发到Extension类加载器。Extension类加载器在jre/lib/ext目录中寻找类文件并尝试加载类文件,如果找到了类文件,这时Extension类加载器将会加载类文件(Application类加载器将永远不会加载类文件);但是如果Extension类加载器没有加载类文件,那么Application类加载器将会从java类路径中加载类文件。请注意:类路径用于加载类文件,而路径用来查找可执行的像javac or java 的命令。
可见性原则
根据可见性原则,子级类加载器可以看到父级类加载器加载的类文件,但是反过来则行不通。这意味着,假如Application类加载器加载了Abc.class 文件,那么尝试使用Extension类加载器去加载Abc.class 文件,则会抛出异常java.lang.ClassNotFoundException。请看下面的示例:
packagetest;
importjava.util.logging.Level; importjava.util.logging.Logger; /** * Java program to demonstrate How ClassLoader works in Java, * in particular about visibilityprinciple of ClassLoader. * * @author Javin Paul */ public class ClassLoaderTest { public static void main(String args[]){ try{ //printingClassLoader of this class System.out.println("ClassLoaderTest.getClass().getClassLoader(): " + ClassLoaderTest.class.getClassLoader()); //tryingto explicitly load this class again using Extension class loader Class.forName("test.ClassLoaderTest",true , ClassLoaderTest.class.getClassLoader().getParent()); }catch(ClassNotFoundExceptionex){ Logger.getLogger(ClassLoaderTest.class.getName()).log(Level.SEVERE,null, ex); } } }
Output:
ClassLoaderTest.getClass().getClassLoader() : sun.misc.Launcher$AppClassLoader@601bb1 16/08/20122:43:48 AM test.ClassLoaderTestmain SEVERE: null java.lang.ClassNotFoundException:test.ClassLoaderTest at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(NativeMethod) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at sun.misc.Launcher$ExtClassLoader.findClass(Launcher.java:229) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) at java.lang.Class.forName0(NativeMethod) at java.lang.Class.forName(Class.java:247) at test.ClassLoaderTest.main(ClassLoaderTest.java:29)
唯一性原则
根据这个原则,一个类文件被父级类加载器加载后,子级类加载器则不能加载它。尽管完全可以编写一个类加载器,它自己加载类文件,这违反了委托和唯一性原则,这样做没有什么好处。在您编写您自己的类加载器时,您应当遵守所有的类加载器原则。
java中如何准确加载类
java 提供了API通过Class.forName(classname) 和Class.forName(classname, initialized, classloader)方法来明确加载一个类,还记得JDBC中用来加载JDBC驱动的方式吗,就是使用该机制来加载对应的类。就像我们在上边例子中展 示的一样,你可以将加载特定类的加载器的名称连同类的二进制名称一起作为参数传进来。Class是通过调用java.lang.ClassLoader的 loadClass()方法,该方法又会调用findClass()方法来为相应类查找对应的字节码。在这个例子中扩展类加载器使用 java.lang.URLClassLoader用来在jar包和目录中查找类文件以及资源。其中,查询中所有以"/"结尾的的都会被当作目录处理。如 果findClass()方法没有找到相关类,那么它会抛出java.lang.ClassNotFoundException异常;如果该方法找到了相 关类,它会调用defineClass()方法来将字节码转换为.class的实例并将该实例返回给调用者。
java中在哪里使用类加载器
在 Java中类加载器是一个强有力的概念,在许多地方都有使用。其中比较流行的一个例子就是applet中用来加载类的AppletClassLoader 类加载器,由于applet是从互联网上加载而不是从本地文件系统中来加载类。通过使用单独的类加载器可以从多个不同的资源中加载多次相同的类,并且这些 类在JVM中会被当作不同的类对待。J2EE使用不同的类加载器从不同的位置来加载类,比如war包中的类是通过Web-app类加载器来加载,而在 EJB-JAR包中绑定的类则通过其他的类加载器加载。而一些web服务器也支持热部署功能,这都是通过实现ClassLoader来达到目的的。同时也 可以使用ClassLoader来从数据库或者其他持久化存储系统中来加载类。
这就是所有关于java中的类加载器及其工作原理。我们已经了解了委托机制、可见性、唯一性原则,这些对代码调试或者解决java中类加载器相关问题时都很重要。总而言之,类加载器工作原理对每一位设计java应用和包的开发者和架构师所必备的知识。
1. 本文由程序员学架构摘译
2. 本文译自http://javarevisited.blogspot.com/2012/12/how-classloader-works-in-java.html?m=1
3. 转载请务必注明本文出自:程序员学架构(微信号:archleaner )
4. 更多文章请扫码:
相关推荐
Java 类加载器原理 Java 类加载器是Java虚拟机(JVM)的核心组成部分,它负责将类的字节码加载到内存中并转换为可执行的Java类。类加载器的作用不仅仅是加载类,还包括确保类的唯一性,避免重复加载,并且遵循特定...
### Java 类加载器详解 #### 一、类加载器概述 在Java中,类加载器(Class ...通过理解和掌握类加载器的工作原理及其不同类型的加载器,可以帮助开发者更好地管理Java应用程序的依赖关系,提高程序的性能和可维护性。
JAVA类加载器的工作原理 JAVA类加载器是JAVA虚拟机(JVM)的一部分,负责加载类文件,并将其转换为JVM可以执行的字节码。类加载器基于三个机制:委托、可见性和单一性。 委托机制是指将加载一个类的请求交给父类...
首先,我们理解一下类加载器的工作原理。Java中的类加载器主要有三种:Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader。它们按照双亲委派模型工作,从根加载器开始,逐级尝试加载类。当我们想要对...
JAVA类加载器的工作原理 Java 类加载器是 Java 虚拟机(JVM)中的一种机制,用于加载 Java 类文件。 Java 类加载器的作用是将类文件加载到 JVM 中,以便 JVM 执行类文件中的字节码。Java 类加载器基于三个机制:...
理解类加载器的工作原理对于深入掌握 Java 语言及其运行机制至关重要。本文将详细探讨 Java 类加载器的概念、类型以及工作流程。 类加载器是 Java 运行时环境中的核心组件,它们不仅负责类的加载,还维护了 Java ...
#### 类加载器的工作原理 Java类加载器遵循按需加载原则,即只有当应用程序真正需要使用某个类时,类加载器才会去加载它。这一机制有效地提高了应用的启动速度,并减少了内存占用。例如,在提供的代码示例中,`Main...
本文主要解析Java类加载的原理,分为三个部分:基础的类加载原理解析、插件环境下的类加载和线程上下文类加载器。 首先,Java虚拟机(JVM)内置了三种预定义的类加载器: 1. 启动(Bootstrap)类加载器:这是最基础的...
了解这一机制对于深入理解Java平台的工作原理至关重要,尤其是在开发自定义类加载器或者处理复杂的依赖管理场景时。 在Java中,类加载主要由三类内置类加载器完成: 1. **引导类加载器(Bootstrap ClassLoader)**...
下面将详细探讨类加载器的工作原理、层次结构以及自定义类加载器的应用。 1. **类加载的生命周期** 类加载的过程包括加载、验证、准备、解析和初始化五个阶段。加载是将类的二进制数据读取到内存中;验证确保类的...
### 类加载器详解 #### 一、类加载器概述 **类加载器(ClassLoader)**是Java虚拟机(JVM)中的一个重要组成部分,它负责将编译好的`.class`文件加载到JVM中...理解类加载器的工作原理对于深入掌握Java编程有着重要意义。
总之,Java的类加载器是理解JVM工作原理的关键一环,其背后涉及到了许多高级特性,如设计模式、动态加载、模块化以及安全性。通过对这些知识点的深入学习,开发者可以更好地控制和优化应用程序的行为。
理解类加载器的工作原理对于深入学习Java编程至关重要。在Java中,类加载器按照层次结构进行组织,包括引导类加载器、扩展类加载器和应用程序类加载器,每个都有特定的职责。 1. **引导类加载器(Bootstrap ...
理解类加载器的工作原理对于处理`ClassNotFoundException`和`NoClassDefFoundError`等异常至关重要。开发人员应该熟悉类加载器的委托模型以及如何在需要时创建自定义类加载器。自定义类加载器通常用于动态加载代码、...
通过掌握类加载的过程、类加载器的工作原理以及类加载的线程安全性等方面的知识,开发者能够更好地利用Java的动态特性,优化程序性能,并避免常见的异常问题,如`ClassNotFoundException`等。此外,对于自定义类加载...
Java 类加载器是Java语言的核心特性之一,它允许程序在运行时动态地加载类到Java虚拟机(JVM)中。这一特性对于实现模块化、插件化和动态部署...理解类加载器的工作原理和层次结构对于解决与类加载相关的问题至关重要。
本文将详细解析Java类加载原理,分为三篇文章进行阐述,分别是:Java类加载原理解析、插件环境下类加载原理解析和线程上下文类加载器。 首先,我们来了解Java虚拟机(JVM)的类加载器结构。JVM预定义了三种主要的类...