`
fred_张浩
  • 浏览: 32188 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java类加载器浅析

    博客分类:
  • JAVA
 
阅读更多
转自:http://www.jfox.info/java-classloader-xq

对于类加载器原理不是很清楚,该文章可以解惑,直接分享了
Java虚拟机中可以安装多个类加载器,系统默认主要有三个类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader。当然也可以自定义类加载器,自定义的加载器必须继承ClassLoader。

类加载器也是Java类,因为其它Java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这个就是BootStrap。BootStrap它是嵌套在Java虚拟机内核中的,jvm启动,这个类就会启动,它是由c++语言编写的。

Java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载。

Java代码

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

    public static void main(String[] args) {
        ClassLoader loader = ClassLoaderTest.class.getClassLoader();

        while (loader != null) {
            System.out.println(loader.getClass().getName());
            loader = loader.getParent();
        }
        System.out.println(loader);
    }
} 
将输出:

Output代码

sun.misc.Launcher$AppClassLoader  
sun.misc.Launcher$ExtClassLoader  
null //null就代表是BootStrap类加载器,该加载器是顶级加载器,没有父类加载器 
深入

在Java中每个类都是由某个类加载器的实体来载入的,因此在Class类的实体中,都会有字段记录载入它的类加载器的实体(当为null时,其实是指Bootstrap ClassLoader)。 在java类加载器中除了引导类加载器(既Bootstrap ClassLoader),所有的类加载器都有一个父类加载器(因为他们本身自己就是java类)。而类的加载机制是遵循一种委托模式:当类加载器有加载类的需求时,会先请求其Parent加载(依次递归),如果在其父加载器树中都没有成功加载该类,则由当前类加载器加载。

Java的类加载器分为以下几种:

(1) Bootstrap ClassLoader

Bootstrap ClassLoader用C++实现,一切的开始,是所有类加载器的最终父加载器。负责将一些关键的Java类,如java.lang.Object和其他一些运行时代码先加载进内存中。

(2) ExtClassLoader

ExtClassLoader用java实现,是Launcher.java的内部类,编译后的名字为:Launcher$ExtClassLoader.class 。此类由Bootstrap ClassLoader加载,但由于Bootstrap ClassLoader已经脱离了java体系(c++),所以Launcher$ExtClassLoader.class的Parent(父加载器)被设置为null;它用于装载Java运行环境扩展包(jre/lib/ext)中的类,而且一旦建立其加载的路径将不再改变。

(3) AppClassLoader

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从ClassLoader类继承而来。比如:URLClassloader是ClassLoader的一个子类,而URLClassloader也是ExtClassLoader和AppClassLoader的父类(注意不是父加载器)。

类加载器之间的父子关系为:

Output代码



BootStrap -> ExtClassLoader -> AppClassLoader (即通常所说的System ClassLoader) 
它们的管辖范围依次是:

ExtClassLoader———->JRE/lib/ext/*.jarAppClassLoader———->CLASSPATH指定的所有jar或目录。

BootStrap------>JRE/lib/rt.jar
类加载器的委托机制

当Java虚拟机要加载一个类时,到底该派哪个类加载器去加载呢?

(1) 首先是当前线程的类加载器去加载线程中的第一个类。

(2) 如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B。

(3) 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不是再去找发起者类加载器的儿子。因为没有getChlid方法,即使有,那么当有多个儿子,找哪一个呢?

那么,能不能自己写个类叫java.lang.System?

一般情况下不能,因为类加载采用委托机制,这样可以保证parent类加载器优先,也就是总是使用parent类加载器能找到的类,这样总是使用java系统提供的System。因为每个类加载器加载类时,又先委托给其上级类加载器,java.lang.System在BootStrap中最先加载。但是我们可以写一个类加载器来加载我们自己写的java.lang.System类。

当需要编写自己的类加载器时:

自定义的类加载器必须继承ClassLoader。
重写loadClass方法与findClass方法。loadClass中先调用父类的loadClass,然后调用findClass,通常情况下只覆盖findClass就可以。
重写defineClass方法。
注:自定义的类加载器通常用于解密自己写的已加密的class字节码,否则即使别人拥有该class文件也无法被系统的类加载器正常加载。
分享到:
评论

相关推荐

    Java类加载原理浅析

    **自定义类加载器**是Java提供的强大特性,允许开发者创建自己的类加载器,实现特定的加载逻辑。例如,你可以实现热部署,动态加载网络上的类,或者对类进行加密解密后再加载等。 除了基础的类加载,还有**类的全...

    [浅析J2EE应用服务器的JAVA类装载器]python回朔异常的模块.docx

    【浅析J2EE应用服务器的JAVA类装载器】 Java类装载器机制是Java语言灵活性的关键组成部分,尤其在J2EE应用服务器中扮演着重要角色。理解这一机制有助于开发者更好地部署和管理应用程序,解决可能出现的部署问题。 ...

    Java类加载机制浅析

    4、类加载器ClassLoader  4.1类加载器分类  5、双亲委派机制   5.1、检查某个类是否已经加载   5.2、加载顺序  5.3、打破双亲委派机制 所谓类加载机制就是 虚拟机把Class文件加载到内存 并对数据进行校验,...

    Java内存分配浅析

    常量池在Java的动态链接中起到关键作用,因为它是解析类、方法和字段引用的依据。 5. **代码段(Code Segment)**:这部分内存用于存储从硬盘上读取的源代码。 6. **数据段(Data Segment)**:存放由`static`...

    基于Java的Web开发技术浅析.pdf

    - JSF:JavaServer Faces是Java EE平台的一部分,提供了一种组件化的方式来构建用户界面,它将视图、模型和控制器分离,使得开发更复杂的企业级Web应用变得更加容易。 3 Java Web 开发框架 随着Java Web开发的复杂...

    浅析ClassLoader

    2. 类加载器分类:Java中的ClassLoader有三种基本类型:Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)和AppClassLoader(应用程序类加载器)。Bootstrap加载JDK核心库,Extension...

    Java 反射机制浅析

    Java反射机制是Java编程语言中一个强大的特性,它允许程序在运行时动态地获取类的信息并操作类的对象。反射机制的核心在于,它打破了编译时的束缚,使得代码具有更高的灵活性和可扩展性。在Java中,反射主要依赖于`...

    深入Java单例模式浅析

    Java中的单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式在许多场景下非常有用,比如配置管理、缓存、日志记录等,因为它们通常只需要一个共享的实例。 1. 最简单的实现: 单例...

    基于Java的Web开发技术浅析 (1).zip

    在本压缩包中的"基于Java的Web开发技术浅析 (1).pdf"可能就包含了关于WAR文件的详细解析,以及如何在Web容器中部署和运行WAR文件的方法。 总的来说,Java Web开发技术是一个庞大的领域,涵盖了从服务器端编程、...

    浅析计算机软件JAVA编程的特点及应用.pdf

    Java提供了丰富的安全性特性,如类加载器的安全检查、运行时数据区域的安全性保护、异常处理机制等,从而有效地防止了恶意代码的执行。此外,Java提供了一套安全管理器和安全策略,允许开发者对不同部分的代码实施...

    浅析Java语言中对象的创建过程.zip

    如果未加载,JVM会通过类加载器找到对应的`.class`文件,进行加载和链接。加载包括找到类的二进制数据,而链接则包括验证、准备和解析三个阶段。 2. **分配内存**:一旦类加载完成,JVM会在堆内存中为新对象分配...

    浅析Java swing组件窗体设计.pdf

    图片加载可以通过Toolkit类的getImage()方法进行,获取图片对象后,可以调用Graphics对象的drawImage()方法将图片绘制到面板上。需要注意的是,在调用drawImage()方法时,可以设置图片的绘制位置以及是否进行缩放。 ...

    浅析计算机软件JAVA编程的特点及应用.zip

    在安全性方面,Java有一套严格的访问控制机制和安全模型,包括类加载器、安全管理器等,可以有效防止恶意代码的执行,保护用户系统的安全。此外,Java还提供了异常处理机制,使得程序在遇到错误时能够有序地恢复或...

    浅析JAVA_HOME,CLASSPATH和PATH的作用

    CLASSPATH环境变量用于指定Java类加载器搜索类文件(.class文件)的路径。在Java编译和运行过程中,类加载器需要知道到哪些位置去查找需要加载的类。默认情况下,类加载器只会在当前目录下查找,如果类文件不在当前...

    浅析使用模型参数构造Java Swing组件.zip

    你可以自定义一个TableModel类,实现所需的功能,比如从数据库中加载数据或者实现复杂的验证规则。 2. **JList的ListModel**:JList用于显示单列数据,它的数据模型是ListModel。通过实现ListModel接口或使用...

    Java基础知识点 - 内容比较全面

    14. **Java数组浅析**:数组是Java中存储固定数量相同类型元素的集合,支持索引访问。深浅拷贝的概念在数组复制时也会涉及,浅拷贝只复制引用,深拷贝复制整个对象及其内容。 这些知识点构成了Java开发者必备的基础...

    java与php的区别浅析

    Java与PHP的区别浅析 Java是一种通用的面向对象编程语言,旨在生成可在任何地方使用相同代码的代码。这种编程语言是基于类的,面向对象的和人类可读的。它支持服务器端和客户端。Java既可以编译也可以解释。Java...

    浅析对Java关键字final和static的理解

    - **final静态变量**(常量):这类变量在类加载时初始化,并在整个程序运行期间保持不变。通常用于定义程序中的常量,如PI值等,它们是全类共享的。 - **final局部变量**:在方法或块中定义的`final`变量,一旦...

    深入浅析Java中的final关键字

    此外,`final`类成员变量如果是`static`类型的,它将在类加载时初始化。 2. 编译期常量 对于`final`修饰的基本类型和`String`类型的变量,如果它们的值在编译时就能确定,编译器会将其视为编译期常量。这意味着...

Global site tag (gtag.js) - Google Analytics