除了自定义的类加载之外,jvm存在三种类加载器,并以一种父委托的加载机制进行加载。

--启动类加载器,又称根加载器,是一个native的方法,使用c++实现。在java中我们用null标识,用于加载jdk自带的类。

--扩展类加载器,用于加载jdk扩展类

--系统类加载器,用于加载classpath目录下的类


上面提到的三种类加载器,是存在父子关系,即系统类加载器会委托extension加载器,如果extension加载器不能加载该类的话,再由系统类加载器进行加载。注意这里所说的父子关系不是指继承关系,而是一种组合关系。至于为什么要使用这种父委托加载机制呢?

一个显而易见的好处就是Java类伴随着它的类加载器一起具备了一种带有优先级带层次关系,列如类java.lang.Object,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载的,因此Object类在程序的各种类加载器环境中是同一个类。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个成为java.lang.Object的类,并放在程序的classpath下面,那系统将出现多个Object类,java类型体系中最基础的行为也就无法保证类,应用程序也将会变得一片混乱。


实现一个自定义类加载器只需继承ClassLoader,重写findClass()方法

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream; /**
* @desc
* @author chenqm
* @date 2016年2月17日
*/
public class MyClassLoader extends ClassLoader { private String name; //类加载器的名字
private String path = "d:\\"; //加载类的路径
private String fileType = ".class";//Class文件的扩展名
public MyClassLoader(String name){
super();
this.name = name;
} public MyClassLoader(ClassLoader parent,String name){
super(parent);//显式制定该类加载器的父加载器
} public String getPath() {
return path;
} public void setPath(String path) {
this.path = path;
} @Override
public Class<?> findClass(String name) throws ClassNotFoundException{
byte[] data = this.loadClassData(name);
return this.defineClass(name, data, 0, data.length);
} private byte[] loadClassData(String name){
InputStream is = null; byte[] data = null; ByteArrayOutputStream baos = null; try{
name = name.replace(".", "\\");
is = new FileInputStream(path + name +fileType);
baos = new ByteArrayOutputStream();
int ch =0 ;
while(-1 !=(ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
is.close();
baos.close();
}catch(Exception e){
e.printStackTrace();
}
} return data;
} @Override
public String toString() {
// TODO Auto-generated method stub
return name;
} public static void main(String[] args) throws Exception{
MyClassLoader loader1 = new MyClassLoader("loader1");
loader1.setPath("d:\\myapp\\serverlib\\");
MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");
loader2.setPath("d:\\myapp\\clientlib\\");
MyClassLoader loader3 = new MyClassLoader(null,"loader3");
loader3.setPath("d:\\myapp\\otherlib\\");
test(loader1);
test(loader2);
test(loader3);
} public static void test(ClassLoader loader) throws Exception{
Class clazz = loader.loadClass("Simple");
Object o = clazz.newInstance();
}
}

这里我自定了一个类加载器,用于加载simple类

/**
* @desc
* @author chenqm
* @date 2016年2月17日
*/
public class Simple {
public Simple(){
System.out.println("Sample is loaded by:"+this.getClass().getClassLoader());
Dog dog = new Dog();
System.out.println("Dog is loaded by:"+dog.getClass().getClassLoader());
}
}

给出dog类:

/**
* @desc
* @author chenqm
* @date 2016年2月17日
*/
public class Dog { }

然后把Dog.class与Simple.class文件放到d:\myapp\serverlib 和d:\myapp\clientlib(两个路径下均有两个class),将MyClassLoader文件放到d:\myapp\otherlib下面。

进入d:\myapp\otherlib 执行java MyClassLoader

得到结果:

Sample is loaded by:loader1
Dog is loaded by:loader1
Sample is loaded by:loader1
Dog is loaded by:loader1
java.io.FileNotFoundException: d:\myapp\otherlib\Simple.class (No such file or directory)

简单分析一下,请注意MyClassLoader的main方法,有三个自定类加载器loader1(父加载器是系统类加载器),loader2(父加载器是loader1),loader3(父加载器是根加载器)。

test方法:用指定的类加载器去加载simple类。

--用loader1去加载simple类的时候,loader1的父加载器是系统类加载器,系统类加载器肯定无法加载simple类,为什么呢?前面说了,系统类加载器用于加载classpath下的类,而classpath默认是什么?  "."就是当前路径,而当前路径不存在simple类,所以进而由loader1加载。

--loader2的父加载器是loader1,所以根据父委托加载机制,理应由loader1去加载simple类。

--loader3的父加载器是根加载器,根加载器是不会加载我们自定义的类文件的,所以加载的重任就交给了loader3,但是loader3的目录下,不存在simple.class文件,没办法了,父亲干不了,自己也干不了,那只能抛异常咯。

												

最新文章

  1. 【手记】为windows2008建个睡眠快捷方式
  2. Scala 笔记
  3. 【腾讯Bugly干货分享】微信小程序开发思考总结——腾讯“信用卡还款”项目实践
  4. [Python] python vs cplusplus
  5. extjs组件添加事件监听的三种方式
  6. 2.6---找有环链表的开头结点(CC150)
  7. create和grant配合使用,对Mysql进行创建用户和对用户授权
  8. Magcodes.WeiChat——通过CsvFileResult以及DataAnnotations实现导出CSV文件
  9. 给C#的treeview控件的部分节点添加checkbox
  10. iOS个别界面旋转问题
  11. 新闻滚动marquee标签
  12. Oracle如何只显示重复数据,或不显示重复数据
  13. oracle重新启动步骤
  14. Mysql++详解
  15. SQL Server2008数据库中删除用户,提示数据库主体在该数据库中拥有 架构,无法删除
  16. HTML5和CSS3
  17. 自动生成getter,setter方法的插件lombok
  18. selenium中的下拉框处理模块Select
  19. Python脱产8期 Day09 2019/4/23
  20. XamarinSQLite教程Xamarin.iOS项目中打开数据库文件

热门文章

  1. ie7,8常见bug,共计257个bug汇总?如何解决ie的历史bug
  2. Android(5)— Mono For Android 两个功能型外包
  3. [Asp.net 开发系列之SignalR篇]专题一:Asp.net SignalR快速入门
  4. SQL 行列倒置
  5. 解决Win7 软件图标不显示--Win7图标异常,快捷方式不显示解决方法
  6. [翻译].NET随机数
  7. Yii Model中添加默认搜索条件
  8. Open Source Cassandra Gitbook for Developer
  9. zk系列-zookeeper的使用
  10. 爱上MVC~为非法进行Action的用户提供HttpStatusCodeResult