Java-ClassLoader学习笔记

以下笔记整理自《Java程序员面试宝典》以及博客JVM工作原理和流程

一、ClassLoader基本概念

与C或C++编写的程序不同,Java程序并不是一个可执行文件,而是由许多独立的类文件组成的,每一个文件对应一个Java类。此外,这些类文件并非全部装入内存,而是根据程序需要逐渐载入。JVM的类加载是通过ClassLoader及其子类来完成的,有关JVM的工作原理、类加载的工作流程以及Java的内存机制可以参看:JVM工作原理和流程

 

二、ClassLoader加载流程

       

同样,具体流程的解析可参看:JVM工作原理与流程

 

三、一些重要的方法

1. loadClass方法

ClassLoader.loadClass()是ClassLoader的入口点,该方法的定义如下:

Class loadClass(String name, boolean resolve);

name是指JVM需要的类的名称,resolve参数告诉方法是否需要解析类。在准备执行类之前,应考虑解析类。注意:并不总是需要解析,如果JVM只需要知道该类是否存在或找出该类的超类,那么就不需要解析。

 

2. defineClass方法

defineClass方法接受由原始字节组成的数组,并把它转换成Class对象。原始数组包含如从文件系统或网络装入的数据。defineClass管理JVM的许多复杂的实现层面——它把字节码分析称运行时数据结构、检验有效性等。因为defineClass方法被标记成final,所以不能覆盖它。

 

3. findSystemClass方法

findSystemClass方法从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就使用defineClass将原始字节转换成Class对象,以将该文件转换成类。当运行Java应用程序时,这是JVM正常装入类的默认机制。对于定制的ClassLoader,只有在尝试其他方法装入类之后,再使用findsystemClass。这是因为ClassLoader是负责执行装入类的相关步骤,不负责所有类的所有信息。

 

4. resolveClass方法

正如前面所提到的,可以不完全地(不带解析)装入类,也可以完全地(带解析)装入类。当编写我们自己的loadClass时,可以调用resolveClass,这取决于loadClass的resolve参数的值。

 

5. findLoadedClass方法

findLoadedClass充当一个缓存:当请求loadClass装入类时,它调用该方法来查看ClassLoader是否已装入这个类,这样可以避免重新装人已有类所造成的麻烦。

 

6. findClass方法

loadClass默认实现调用该方法。findClass的用途包含ClassLoader的所有特殊代码,而无需复制其他代码。

findClass目的是从本地文件系统使用实现的类装载器装载一个类。为了创建自己的类装载器,应该扩展ClassLoader类,比如可以创建一个FileClassLoader extends ClassLoader,然后覆盖ClassLoader中的findClass(String name)方法,这个方法通过类的名字得到一个Class对象。

public Class findClass(String name){
    byte[] data = loadClassData(name);
    return defineClass(name, data, 0, data.length);
}

 

7. findSystemClass方法

如果覆盖findClass或loadClass,getSystemClassLoader能以实际的ClassLoader对象访问系统ClassLoader(而不是固定地从findSystemClass调用它)。为了将类请求委托给父类ClassLoader,这个新方法允许ClassLoader获取她的父类ClassLoader。当使用特殊方法,定制的ClassLoader不能找到类时,可以使用这种方法。父类ClassLoader被定义成创建该ClassLoader所包含代码的对象的ClassLoader。

 

8. forName方法

Class类中有一个静态方法forName,这个方法和ClassLoader中的loadClass方法的目的一样,都是用来加载类的,但两者的作用有所区别。

Class clazz = Class.forName("something");
或者
ClassLoader c1 = Thread.currentThread().getContextClassLoader();
Class clazz = c1.loadClass("something");

Class.forName()调用Class.forName(name, initialize, loader);也就是Class.forName("something")等同于Class.forName("something", true, CALLCLASS.class.getClassLoader())。

第二个参数true是用来设置加载类的时候是否连接该类,true就连接,否则不连接。关于连接,JVM在加载类时,需要经过三个步骤:装载、连接、初始化。装载就是找到相应的class文件,读入JVM;初始化就是class文件初始化。下面介绍一下连接,分为三步:

第一步是验证class是否符合规格。第二步是准备,就是为类变量分配内存的同时设置默认初始值。第三步就是解释,这一步是可选的,根据loadClass方法的第二个参数来判定是否需要解释。这里的解释是指根据类中的符号引用查找相应的实体,再把符号引用替换成一个直接引用的过程。

在Java API文档中,loadClass方法实际上是调用了两个参数,第二个参数默认为false。因此,可以看出loadClass加载类实际上就是加载的时候并不对该类进行解释,因此不会初始化该类。而Class类的forName方法则相反,会将Class进行解释和初始化。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值