JVM-ClassLoader

来源:互联网 发布:成都电视台网络直播 编辑:程序博客网 时间:2024/06/06 00:35

1. ClassLoader基本概念

与C或c++编写的程序不同,Java程序并不是一个可执行文件,而是由许多独立的类文件组成的,每一个文件对应一个Java类。此外,这些类文件并非全部都装入内存,而是根据程序需要遵渐载入。ClassLoader是JVM实现的一部分。
ClassLoader包括:
bootstrap classloader(启动类加栽器),ClassLoader在JVM运行的时候加载Java核心的API,以满足Java程序最基本的需求,其中就包括用户定义的ClassLoader,这里所谓的用户定义,是指通过Java程序实现的两个ClassLoader: -个ExtClassLoader,它的作用是用采加载Java的扩展API,也就是,lib/ext中的类;第二个是AppClassLoader,它是用来加载用户机器上CLASSPATH设置目录中的Class类,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoadcr进行加载。

2.ClassLoader加载流程

当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载Java核心API(ExtClassLoader和AppClassLoader也在此时被加栽),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。

3.类加载的过程->父类委托模式

loadClass{//首先检查该name的class是否被加载Class c=findLoadClass(name);if(c==null){    if(parent!=null){        //如果parent不为null,则调用parent的loadClass进行加载        c=parent.loadClass(name,false);    }else{        //如果parent为null,则调用BootstrapClassLoader进行加载        c=findBootstrapClass(name);    }}//如果仍然没有加载成功,则调用自身的findClass进行加载c=findClass(name);if(resolve){    reaolveClass(c);}return c;}

从上面一段代码中可以看出,一个类加载的过程使用了一种父类委托模式。
为什么要使用这种父类委托模式呢?
1.这样可以避免重复加载,当父类已经加栽了该类的时候,就没有必要子ClassLoader再加载一次。
2.考虑到安全因素,如果不使用这种委托模式,那么可以随时使用自定义的String来动态替代Java核心API中定义的类型,这样会存在非常大的安全隐患,而父类委托的方式就可以避免这种情况,因为String已经在启动时被加载,所以,用户由定义类是无法加载一个自定义的ClassLoader。

重要方法

1. loadClass方法

ClassLoader.loadClass0是ClassLoader的入口点。该方法的定义如下:

Class loadClass(  String name, boolean resolve)

2. defineClass方法

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

3. findSystemClass方法。

findSystemClass方法从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就使用defineClsass将原始字节转换成Class对象,以将该文件转换成类。当运行Java应用程序时,这是JVM正常装入类的默认机制。对于
定制的ClassLoader,只有在尝试其他方法装入类之后,再使用findSystemClass。
这是因为ClassLoader是负责执行装入类的相关步骤,不负责所有类的所有信息。例如,即使ClassLoader从远程的Web站点装入了某些类,仍然需要在本地机器上装入大量的基本Java库。而这些类库不是我们所关心的,所以要JVM以默认
方式从本地文件系统装入它们,这就是findSystemClass的用途。

4. resolveClass方法

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

5. findLoadedClass方法

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

6.findClass方法:

loadClass默认实现调用这个新方法。findClass的用途包含ClassLoader的所有特殊代码,而无须要复制其他代码(例如,当专门的方法失败时,调用系统ClassLoader)。

为了创建自己的类装载器,应该扩展ClassLoader类,这是一个抽象类,可以创建一个
FileClassLoaderextends ClassLoader,然后覆盖ClassLoader中的findClass( String name)方法,这个方法通过类的名字而得到一个Class对象。

这里写图片描述

8) forName方法

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

这里写图片描述

这里写图片描述

在Java API文档中,loadClass方法的定义是protected,也就是说,该方法是被保护的,而用户使用的方法是一个参数,一个参数的loadclass方法实际上就是调用了两个参数,第二个参数默认为false。因此,在这里可得看出通过loadClass加载类实际上就是加载的时候并不对谊类进行解释,因此不会初始化该类。而Class粪的forName方法则相反,使用forName加载的时候就会将Class进行解释和初始化。

下 面给出的Java中ClassLoader中的描述,哪些描述是正确的? ( )
A. ClassLoader没有层次关系
B.所有类中的ClassLoader都是AppClassLoader
c.通过Class.forName(String className),能够动态加载一个类
D.不同的ClassLoader加载同一个Class文件,所得的类是相同的

0 0