JAVA 类的加载器,java加载
JAVA 类的加载器,java加载
JVM三种预定义类型类加载器:
启动(Bootstrap)类加载器:引导类装入器是用本地代码实现的类装入器,它负责将<Java_Runtime_Home>/lib 下面的类库加载到内存中,但是虚拟机出于安全等因素考虑,不会加载< Java_Runtime_Home >/lib存在的陌生类,开发者通过将要加载的非JDK自身的类放置到此目录下期待启动类加载器加载是不可能的。
标准扩展(Extension)类加载器:扩展类加载器是由 Sun 的ExtClassLoader(sun.misc.Launcher$ExtClassLoader) 实现的。它负责将 < Java_Runtime_Home >/lib/ext 或者由系统变量 java.ext.dir 指定位置中的类库加载到内存中。
系统(System)类加载器:系统类加载器是由 Sun 的AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。AppClassLoader是加载Classpath中配置的类库
类加载器基本概念
顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。
一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成java.lang.Class
类的一个实例。每个这样的实例用来表示一个
Java 类。通过此实例的 newInstance()
方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如
Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。基本上所有的类加载器都是 java.lang.ClassLoader
类的一个实例。
java.lang.ClassLoader
类介绍
java.lang.ClassLoader
类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个
Java 类,即 java.lang.Class
类的一个实例。除此之外,ClassLoader
还负责加载
Java 应用所需的资源,如图像文件和配置文件等。不过本文只讨论其加载类的功能。ClassLoader 中与加载类相关的方法
方法 | 说明 |
---|---|
getParent() |
返回该类加载器的父类加载器。 |
loadClass(String
name) |
加载名称为 name 的类,返回的结果是 java.lang.Class 类的实例。 |
findClass(String
name) |
查找名称为 name 的类,返回的结果是 java.lang.Class 类的实例。 |
findLoadedClass(String
name) |
查找名称为 name 的已经被加载过的类,返回的结果是 java.lang.Class 类的实例。 |
defineClass(String
name, byte[] b, int off, int len) |
把字节数组 b 中的内容转换成
Java 类,返回的结果是 java.lang.Class 类的实例。这个方法被声明为 final 的。 |
resolveClass(Class<?>
c) |
链接指定的 Java 类。 |
类加载器的树状组织结构
每个 Java 类都维护着一个指向定义它的类加载器的引用,通过getClassLoader()
方法就可以获取到此引用。通过递归调用getParent()
方法来输出全部的父类加载器。public class ClassLoaderTree {
public static void main(String[] args) {
ClassLoader loader = ClassLoaderTree.class.getClassLoader();
while (loader != null) {
System.out.println(loader.toString());
loader = loader.getParent();
}
}
}
开发自己的类加载器
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
}
else {
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] getClassData(String className) {
String path = classNameToPath(className);
try {
InputStream ins = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = ins.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String classNameToPath(String className) {
return rootDir + File.separatorChar
+ className.replace('.', File.separatorChar) + ".class";
}
}
类 FileSystemClassLoader
继承自类 java.lang.ClassLoader
。一般来说,自己开发的类加载器只需要覆写 findClass(String
name)
方法即可。java.lang.ClassLoader
类的方法 loadClass()
封装了前面提到的代理模式的实现。该方法会首先调用 findLoadedClass()
方法来检查该类是否已经被加载过;如果没有加载过的话,会调用父类加载器的 loadClass()
方法来尝试加载该类;如果父类加载器无法加载该类的话,就调用 findClass()
方法来查找该类。因此,为了保证类加载器都正确实现代理模式,在开发自己的类加载器时,最好不要覆写 loadClass()
方法,而是覆写 findClass()
方法。
类 FileSystemClassLoader
的 findClass()
方法首先根据类的全名在硬盘上查找类的字节代码文件(.class
文件),然后读取该文件内容,最后通过 defineClass()
方法来把这些字节代码转换成 java.lang.Class
类的实例。
相关文章
- 暂无相关文章
用户点评