java是 具有动态性,什么是动态性?有个最直观的例子:windows系统的即插即用,支持即插即用的设备可以在系统不重新启动的情况下既可以热把插使用。而 java的动态性表现在:我们的程序可以不用全盘的重新编译就能对程序某部分进行更新,C#也和java一样具有动态性,而且它的这种动态性表现更为直 观:直接生成windows的动态连接库文件——dll文件。而java生成的是class文件,class是怎么实现动态性的了,这个时候就全靠我们今 天的主角:java的类加载器。
我们都知道所有的java类都是继承了object这个类,在object这个类中有一个方法:getclass(),这个方法返回的是一个Class类对象,具体见:认识java的Class类
一旦一个类被载入JVM中,同一个类就不会被再次载入了(切记,同一个类)。这里存在一个问题就是什么是“同一个类”?正如一个对象有一个具体的状态,即标识,一个对象始终和其代码(类)相关联(见文认识java的Class类)。 同理,载入JVM的类也应该有一个具体的标识,我们知道:在JAVA中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名是包名和类名。不过在JVM中一个类是用其全名再附加上一个加载类ClassLoader的实例作为唯一标识。 因此,如果一个名为Pg的包中,有一个名为Cl的类,被类加载器KlassLoader的一个实例对象kl1加载,生成Cl的对象,即 C1.class(这里指类,而非对象)在JVM中表示为(Cl, Pg, kl1)。这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它们所加载的类也因此完全不同,互不兼容的。
在java中每个类都是由某个类加载器的实体来载入的,因此在Class类的实体中,都会有字段记录载入它的类加载器的实体(当为null时,其实是指 Bootstrap ClassLoader)。 在java类加载器中除了引导类加载器(既Bootstrap ClassLoader),所有的类加载器都有一个父类加载器(因为他们本身自己就是java类)。而类的加载机制是遵循一种委托模式:当类加载器有加载 类的需求时,会先请求其Parent加载(依次递归),如果在其父加载器树中都没有成功加载该类,则由当前类加载器加载。
java的类加载器分为以下几种:
1,Bootstrap ClassLoader,用C++实现,一切的开始,是所有类加载器的最终父加载器。负责将一些关键的Java类,如java.lang.Object和其他一些运行时代码先加载进内存中。
2,ExtClassLoader,用java实现,是Launcher.java的内部类,编译后的名字 为:Launcher$ExtClassLoader.class 。此类由Bootstrap ClassLoader加载,但由于Bootstrap ClassLoader已经脱离了java体系(c++),所以Launcher$ExtClassLoader.class的Parent(父加载器) 被设置为null;它用于装载Java运行环境扩展包(jre/lib/ext)中的类,而且一旦建立其加载的路径将不再改变。
3,AppClassLoader,用java实现,也是是Launcher.java的内部类,编译后的名字 为:Launcher$AppClassLoader.class 。AppClassLoader是当Bootstrap ClassLoader加载完ExtClassLoader后,再被Bootstrap ClassLoader加载。所以ExtClassLoader和AppClassLoader都是被Bootstrap ClassLoader加载,但AppClassLoader的Parent被设置为ExtClassLoader。可见Parent和由哪个类加载器来 加载不一定是对应的。
个类装载器是我们经常使用的,可以调用ClassLoader.getSystemClassLoader() 来获得,如果程序中没有使用类装载器相关操作设定或者自定义新的类装载器,那么我们编写的所有java类都会由它来装载。而它的查找区域就是我们常常说到 的Classpath,一旦建立其加载路径也不再改变。
4,ClassLoader:一般我们自定义的ClassLoader从ClassLoader类继承而来。比如:URLClassloader是 ClassLoader的一个子类,而URLClassloader也是ExtClassLoader和AppClassLoader的父类(注意不是父 加载器)。
让我们先回到java的动态 性,实现java的动态性有两种方法类型:一种是隐式,另一种是显式。什么是隐式?new 这个关键字我们都认识,当我们用其将类实例化时(即将对象载入),这种就是隐式!我们再来看显式的实现方法,一种可以由java.long.Class里 面的forName()方法将类实例化,其中也用到了类加载器,详情见:认识java的Class类,另一种是由也就是直接用类加载器ClassLoader来实现。
ClassLoader一些重要的方法
A) 方法 loadClass
ClassLoader.loadClass() 是 ClassLoader 的入口点。该方法的定义如下:
Class loadClass( String name, boolean resolve );
参数name JVM 需要的类的名称,如 Person 或 java.lang.Object。
参数 resolve 参数告诉方法是否需要解析类。在准备执行类之前,应考虑类解析。并不总是需要解析。如果 JVM 只需要知道该类是否存在或找出该类的超类,那么就不需要解析详情见:认识java的Class类 中的forName()方法的介绍。
B) 方法 defineClass
defineClass 方法是 ClassLoader 的主要诀窍。该方法接受由原始字节组成的数组并把它转换成 Class 对象。原始数组包含如从文件系统或网络装入的数据。defineClass 管理 JVM 的许多复杂、神秘和倚赖于实现的方面 -- 它把字节码分析成运行时数据结构、校验有效性等等。不必担心,您无需亲自编写它。事实上,即使您想要这么做也不能覆盖它,因为它已被标记成final的。
C) 方法 findSystemClass
findSystemClass 方法从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就使用 defineClass 将原始字节转换成 Class 对象,以将该文件转换成类。当运行 Java 应用程序时,这是 JVM 正常装入类的缺省机制。(Java 2 中 ClassLoader 的变动提供了关于 Java 版本 1.2 这个过程变动的详细信息。) 对于定制的 ClassLoader,只有在尝试其它方法装入类之后,再使用 findSystemClass。原因很简单:ClassLoader 是负责执行装入类的特殊步骤,不是负责所有类。例如,即使 ClassLoader 从远程的 Web 站点装入了某些类,仍然需要在本地机器上装入大量的基本 Java 库。而这些类不是我们所关心的,所以要 JVM 以缺省方式装入它们:从本地文件系统。这就是 findSystemClass 的用途。
D) 方法 resolveClass
正如前面所提到的,可以不完全地(不带解析)装入类,也可以完全地(带解析)装入类。当编写我们自己的 loadClass 时,可以调用 resolveClass,这取决于 loadClass 的 resolve 参数的值。
E) 方法 findLoadedClass
findLoadedClass 充当一个缓存:当请求 loadClass 装入类时,它调用该方法来查看 ClassLoader 是否已装入这个类,这样可以避免重新装入已存在类所造成的麻烦。应首先调用该方法。
怎么组装这些方法
1) 调用 findLoadedClass 来查看是否存在已装入的类。
2) 如果没有,那么采用那种特殊的神奇方式来获取原始字节。
3) 如果已有原始字节,调用 defineClass 将它们转换成 Class 对象。
4) 如果没有原始字节,然后调用 findSystemClass 查看是否从本地文件系统获取类。
5) 如果 resolve 参数是 true,那么调用 resolveClass 解析 Class 对象。
6) 如果还没有类,返回 ClassNotFoundException。
Java 2 中 ClassLoader 的变动
1)loadClass 的缺省实现
定制编写的 loadClass 方法一般尝试几种方式来装入所请求的类,如果您编写许多类,会发现一次次地在相同的、很复杂的方法上编写变量。 在 Java 1.2 中 loadClass 的实现嵌入了大多数查找类的一般方法,并使您通过覆盖 findClass 方法来定制它,在适当的时候 findClass 会调用 loadClass。 这种方式的好处是您可能不一定要覆盖 loadClass;只要覆盖 findClass 就行了,这减少了工作量。
2)新方法:findClass
loadClass 的缺省实现调用这个新方法。findClass 的用途包含您的 ClassLoader 的所有特殊代码,而无需要复制其它代码(例如,当专门的方法失败时,调用系统 ClassLoader)。
3) 新方法:getSystemClassLoader
如果覆盖 findClass 或 loadClass,getSystemClassLoader 使您能以实际 ClassLoader 对象来访问系统 ClassLoader(而不是固定的从 findSystemClass 调用它)。
4) 新方法:getParent
为了将类请求委托给父代 ClassLoader,这个新方法允许 ClassLoader 获取它的父代 ClassLoader。当使用特殊方法,定制的 ClassLoader 不能找到类时,可以使用这种方法。
父代 ClassLoader 被定义成创建该 ClassLoader 所包含代码的对象的 ClassLoader。
相关推荐
关于Java类加载器的探讨 Java类加载器是Java技术系统中核心的部分,它们之间存在继承关系。引导类加载器负责加载jdk中的系统类,扩展类加载器负责加载标准扩展类,而系统类加载器负责加载classpath中的类。 一、类...
### Java 类加载器详解 #### 一、类加载器概述 在Java中,类加载器(Class Loader)是一项核心机制,用于将字节码(.class文件)加载到JVM中,使其成为运行时的对象。类加载器不仅实现了类的加载功能,还确保了...
Java 类加载器原理 Java 类加载器是Java虚拟机(JVM)的核心组成部分,它负责将类的字节码加载到内存中并转换为可执行的Java类。类加载器的作用不仅仅是加载类,还包括确保类的唯一性,避免重复加载,并且遵循特定...
类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java ...
Java 类加载器是Java运行时环境的一个重要组成部分,它的主要职责是将编译后的字节码(.class文件)加载到JVM中,使得程序能够运行。类加载器的机制保证了类的唯一性,同时也提供了灵活性,允许我们自定义加载逻辑。...
### Java类加载器详解 Java类加载器是Java运行时环境的一个关键组成部分,负责将类文件(.class)从各种来源加载到JVM中。它不仅管理类的生命周期,还确保了类的正确加载和初始化,是Java动态特性的基石。 #### 类...
Java类加载器是Java虚拟机(JVM)的关键组成部分,它负责查找并加载类到内存中,使得程序能够运行。自定义Java类加载器允许我们根据特定需求扩展默认的加载机制,例如,从非标准位置加载类或者实现动态加载。在Java...
Java 类加载器是Java虚拟机(JVM)的核心组成部分,它负责将编译后的字节码文件(.class文件)加载到JVM中并转换为运行时的数据结构。Tomcat,作为广泛使用的Java Servlet容器,它自定义了一套类加载机制,以满足Web...
**类加载器(ClassLoader)**是Java虚拟机(JVM)中的一个重要组成部分,它负责将编译好的`.class`文件加载到JVM中,使得这些类可以在Java环境中运行。类加载器不仅能够加载类,还能够根据不同的需求定制加载方式,如从...
Java的类加载器是Java虚拟机(JVM)的核心组件之一,它负责将类的字节码文件从文件系统或网络中加载到JVM中,然后进行校验、解析和初始化,使得Java程序能够运行。类加载器的概念是Java动态加载和运行时类重定义的...
Java中的类加载器是JVM(Java虚拟机)的核心组件之一,它们负责将.java源代码编译成的.class字节码文件加载到JVM中,从而使得程序能够运行。类加载器不仅涉及到程序的正常执行,还与Java的动态加载、模块化系统以及...
java类加载器学习三、类加载器的委托模式
Java应用程序类加载器是Java平台的核心组成部分之一,它负责加载应用程序中的类到JVM(Java虚拟机)中,使得程序能够执行。理解类加载器的工作原理对于深入学习Java编程至关重要。在Java中,类加载器按照层次结构...
Java 类加载器是 Java 运行时环境中不可或缺的组成部分,负责将 .class 文件加载到 JVM 中。理解类加载器的工作原理对于深入掌握 Java 语言及其运行机制至关重要。本文将详细探讨 Java 类加载器的概念、类型以及工作...
【深入探讨 Java 类加载器】 Java 类加载器是Java虚拟机(JVM)的核心组成部分,它的主要任务是将Java类的字节码加载到JVM中以便执行。类加载器的概念始于JDK 1.0,最初是为了解决Java Applet在浏览器中的运行需求...
深入探讨 Java 类加载器.wps深入探讨 Java 类加载器.wps深入探讨 Java 类加载器.wps
通过掌握类加载的过程、类加载器的工作原理以及类加载的线程安全性等方面的知识,开发者能够更好地利用Java的动态特性,优化程序性能,并避免常见的异常问题,如`ClassNotFoundException`等。此外,对于自定义类加载...
Java 类加载器是Java语言的核心特性之一,它允许程序在运行时动态地加载类到Java虚拟机(JVM)中。这一特性对于实现模块化、插件化和动态部署等功能至关重要。类加载器的设计遵循“分层加载”原则,形成了一个树状的...