JVM规范定义了两种类型的类装载器:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)。

一. ClassLoader基本概念


1.ClassLoader分类


类装载器是用来把类(class)装载进JVM的。


JVM规范定义了两种类型的类装载器:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)。

JVM在运行时会产生三个ClassLoader:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.Bootstrap是用C++编写的,我们在Java中看不到它,是null,是JVM自带的类装载器,用来装载核心类库,如java.lang.*等。


AppClassLoader的Parent是ExtClassLoader,而ExtClassLoader的Parent为Bootstrap ClassLoader。

Java提供了抽象类ClassLoader,所有用户自定义类装载器都实例化自ClassLoader的子类。 System Class Loader是一个特殊的用户自定义类装载器,由JVM的实现者提供,在编程者不特别指定装载器的情况下默认装载用户类。系统类装载器可以通过ClassLoader.getSystemClassLoader() 方法得到。

例1,测试你所使用的JVM的ClassLoader


/*LoaderSample1.java*/


public class LoaderSample1 {


public static void main(String[] args) {


Class c;


ClassLoader cl;


cl = ClassLoader.getSystemClassLoader();


System.out.println(cl);


while (cl != null ) {


cl = cl.getParent();


System.out.println(cl);


}


try {


c = Class.forName( " java.lang.Object " );


cl = c.getClassLoader();


System.out.println( " java.lang.Object's loader is " + cl);


c = Class.forName( " LoaderSample1 " );


cl = c.getClassLoader();


System.out.println( " LoaderSample1's loader is " + cl);


} catch (Exception e) {


e.printStackTrace();


}


}


}

在我的机器上(Sun Java 1.4.2)的运行结果


sun.misc.Launcher$AppClassLoader@1a0c10f


sun.misc.Launcher$ExtClassLoader@e2eec8


null 


java.lang.Object's loader is null


LoaderSample1's loader is sun.misc.Launcher$AppClassLoader@1a0c10f


第一行表示,系统类装载器实例化自类sun.misc.Launcher$AppClassLoader 


第二行表示,系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader 


第三行表示,系统类装载器parent的parent为bootstrap 


第四行表示,核心类java.lang.Object是由bootstrap装载的 


第五行表示,用户类LoaderSample1是由系统类装载器装载的

二.命名空间及其作用


每个类装载器有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的reference,还是可以访问另一命名空间的类。

例2演示了一个命名空间的类如何使用另一命名空间的类。在例子中,LoaderSample2由系统类装载器装载,LoaderSample3由自定义的装载器loader负责装载,两个类不在同一命名空间,但LoaderSample2得到了LoaderSample3所对应的Class对象的reference,所以它可以访问LoaderSampl3中公共的成员(如age)。


例2不同命名空间的类的访问


/*LoaderSample2.java*/


import java.net. * ;


import java.lang.reflect. * ;


public class LoaderSample2 {


public static void main(String[] args) {


try {


String path = System.getProperty( " user.dir " );


URL[] us = { new URL( " file:// " + path + " /sub/ " )};


ClassLoader loader = new URLClassLoader(us);


Class c = loader.loadClass( " LoaderSample3 " );


Object o = c.newInstance();


Field f = c.getField( " age " );


int age = f.getInt(o);


System.out.println( " age is " + age);


} catch (Exception e) {


e.printStackTrace();


}


}


}

/*sub/Loadersample3.java*/


public class LoaderSample3 {


static {


System.out.println( " LoaderSample3 loaded " );


}


public int age = 30 ;


}

编译:javac LoaderSample2.java; javac sub/LoaderSample3.java


运行:java LoaderSample2


LoaderSample3 loaded


age is 30


从运行结果中可以看出,在类LoaderSample2中可以创建处于另一命名空间的类LoaderSample3中的对象并可以访问其公共成员age。


运行时包(runtime package)


由同一类装载器定义装载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看的定义类装载器是否相同。只有属于同一运行时包的类才能互相访问包可见的类和成员。这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类java.lang.Yes,并用用户自定义的类装载器装载,由于java.lang.Yes和核心类库java.lang.*由不同的装载器装载,它们属于不同的运行时包,所以java.lang.Yes不能访问核心类库java.lang中类的包可见的成员。

总结


命名空间并没有完全禁止属于不同空间的类的互相访问,双亲委托模型加强了Java的安全,运行时包增加了对包可见成员的保护。

二. 扩展ClassLoader方法


我们目的是从本地文件系统使用我们实现的类装载器装载一个类。为了创建自己的类装载器我们应该扩展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);


  }

我们还应该提供一个方法loadClassData(String name),通过类的名称返回class文件的字 


节数组。然后使用ClassLoader提供的defineClass()方法我们就可以返回Class对象了。 


public byte [] loadClassData(String name)


{


FileInputStream fis = null ;


byte [] data = null ;


try 


{


fis = new FileInputStream( new File(drive + name + fileType));


ByteArrayOutputStream baos = new ByteArrayOutputStream();


int ch = 0 ;


while ((ch = fis.read()) != - 1 )


{


baos.write(ch);

}


data = baos.toByteArray();


} catch (IOException e)


{


e.printStackTrace();


}

return data;

}

JAVA的类加载器,详细解释的更多相关文章

  1. Java虚拟机类加载器及双亲委派机制

    所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...

  2. 深入探讨java的类加载器

    类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Ja ...

  3. java自定义类加载器

    前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...

  4. java 中类加载器

    jar 运行过程和类加载机制有关,而类加载机制又和我们自定义的类加载器有关,现在我们先来了解一下双亲委派模式. java 中类加载器分为三个: BootstrapClassLoader 负责加载 ${ ...

  5. java高新技术-类加载器

    1.类加载器及委托机制的深入分析 > 类加载器的作用:一个java文件中的出现的类,首先要把这个类的字节码加载到内存中,这个类的信息放在硬盘的classPath下的class文件中,  把cla ...

  6. java面向对象--类加载器及Class对象

    类加载器 jvm 和 类的关系 当调用 java命令运行一个java程序时,会启动一个java虚拟机进程.同一个jvm的所有线程.所有变量都处于同一个进程里,都使用该jvm进程的内存区. jvm进程终 ...

  7. java ClassLoader类加载器

    原文 首先来了解一下字节码和class文件的区别: 我们知道,新建一个java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java ...

  8. 深入理解Java虚拟机 - 类加载器

    引子:       类加载器(classloader)是独立于虚拟机之外,可以独立实现的代码模块.     OSGi使用了类加载器的这一特点实现其热插拔的特性       Java同C++等语言不通, ...

  9. 分析Java的类加载器与ClassLoader(二):classpath与查找类字节码的顺序,分析ExtClassLoader与AppClassLoader的源码

    先回顾一下classpath classpath的作用: classpath的作用是指定查找类的路径:当使用java命令执行一个类(类中的main方法)时,会从classpath中进行查找这个类. 指 ...

  10. Java的类加载器

    一.类加载器的概念 类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 ...

随机推荐

  1. 05_Elasticsearch 单模式下API的增删改查操作

    05_Elasticsearch 单模式下API的增删改查操作 安装marvel 插件: zjtest7-redis:/usr/local/elasticsearch-2.3.4# bin/plugi ...

  2. 使用git pull时,项目没有更新?

    进入项目目录后,执行 git pull 命令,没有将项目更新,并提示下图: 提示:there is no tracking information for the current branch. 意思 ...

  3. 2013第49周一jsp标签

    2013第49周一jsp标签 今天在调试一些前台页面上的问题,在处理structs标签.jstl标签时遇到了些麻烦,为了调用后台数据字典中的类方法,开始在<c:forEach>中尝试怎么样 ...

  4. bzoj1655 [Usaco2006 Jan] Dollar Dayz 奶牛商店

    Description Farmer John goes to Dollar Days at The Cow Store and discovers an unlimited number of to ...

  5. yum 配置详解(转发)

    一.yum 简介 yum,是Yellow dog Updater, Modified 的简称,是杜克大学为了提高RPM 软件包安装性而开发的一种软件包管理器.起初是由yellow dog 这一发行版的 ...

  6. 理解 Linux 配置文件分类和使用

    理解 Linux 配置文件分类和使用 本文说明了 Linux 系统的配置文件,在多用户.多任务环境中,配置文件控制用户权限.系统应用程序.守护进程.服务和其它管理任务.这些任务包括管理用户帐号.分配磁 ...

  7. Linux硬盘分区和格式化

    分区与格式化   先用fdisk分区,分区完成后再用mkfs格式化并创建文件系统,挂载,磁盘就能使用啦.   分区的原理:        MBR:主引导扇区 主分区表:64bytes,最多只能分四个主 ...

  8. Android学习笔记__3__Android应用程序组成

    Android开发必须要了解构造块,Android应用程序是由里有六个重要组成部分组成的,这六种构造块如下:  ◆Activity ◆Intent Receiver ◆Service ◆Content ...

  9. hdu 5335 Walk Out(bfs+寻找路径)

    Problem Description In an n∗m maze, the right-bottom corner or a written on it. An explorer gets los ...

  10. UILabel+Create

    #import <UIKit/UIKit.h> @interface UILabel (Create) /** * 创建普通Label * * @param frame frame * @ ...