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. Sliding Window Maximum 解答

    Question Given an array of n integer with duplicate number, and a moving window(size k), move the wi ...

  2. 【转】Linux下编译ffmpeg

    1.下载ffmpeg.下载网址:http://www.ffmpeg.org/download.html 2.解压缩tar -zxvf ffmpeg-2.0.1.tar.gz 3.配置,生成Makefi ...

  3. JQuery Ajax 获取数据

    前台页面:   对一张进行查询,删除,添加 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"& ...

  4. qt QSortFilterProxyModel

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' from PyQt4.Qt import * from PyQt4. ...

  5. mysql 使用游标进行删除操作的存储过程

    BEGIN   DECLARE  hprocessInstanceId bigint DEFAULT 0; -- 历史流程实例id   DECLARE  hprocessInstanceIdStart ...

  6. VS2008快捷键_大全

    Ctrl+B,C: 清除全部标签 Ctrl+I: 渐进式搜索 Ctrl+Shift+I: 反向渐进式搜索 Ctrl+F: 查找 Ctrl+Shift+F: 在文件中查找 F3: 查找下一个 Shift ...

  7. kaggle之Grupo Bimbo Inventory Demand

    Grupo Bimbo Inventory Demand kaggle比赛解决方案集合 Grupo Bimbo Inventory Demand 在这个比赛中,我们需要预测某个产品在某个销售点每周的需 ...

  8. Android 打造自己的个性化应用(一):应用程序换肤主流方式的分析与概述

    Android平台api没有特意为换肤提供一套简便的机制,这可能是外国的软件更注重功能和易用,不流行换肤.系统不提供直接支持,只能自行研究. 换肤,可以认为是动态替换资源(文字.颜色.字体大小.图片. ...

  9. SQLLoader7(只导入数据文件的其中几行记录)

    数据文件: D:\oracletest\test1.txt SMITH CLERK ALLEN SALESMAN WARD SALESMAN JONES MANAGER MARTIN SALESMAN ...

  10. Python 线程(threading) 进程(multiprocessing)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...