类加载器(class loader)用来加载 Java 字节码到 java虚拟机中,即类加载器负责读取 Java 字节代码,并转换成 java.lang.Class
类的一个实例。每个这样的实例用来表示一个 Java 类。
在java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器:
BookStrap, ExtClassLoader, AppClassLoader
类加载器也是java类,所以java类加载器本身也要被其它类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap.
java虚拟机中所有的类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定父级类加载器
类加载器之间的父子关系和管辖范围
可以通过下面的测试程序验证类加载器的委托机制:
public class ClassLoderTest1 {
public static void main(String[] args) {
ClassLoader loder = ClassLoderTest1.class.getClassLoader();
while (loder != null) {
System.out.println(loder.getClass().getName());
loder = loder.getParent();
}
}
}
/*
* sun.misc.Launcher$AppClassLoader
* sun.misc.Launcher$ExtClassLoader
*/
从结果可以看出,首先AppClassLoader会加载ClassLoderTest1.class,由于委派机制会先使用其父加载器ExtClassLoader去加载,这就是为什么打印出上面的结果。
下面介绍下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 类。
|
当我们自定义类加载器时会用到上面的方法。
下面我们来自定义加载器实现加载特定目录下面的.class文件。
这里我们来加载lib目录下面的字节码文件。
首先我们来定义一个目标文件
public class ClassLoaderDemo extends Date {
public String toString() {
return "这是被类加载器加载的哦";
}
}
让其实现Date类是便于后面的测试
然后我们开始编写自定义的类加载器了
public class CustomClassLoader extends ClassLoader {
/**
* 复写findClass()方法
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = getClassData(name);
if (data == null) {
throw new ClassNotFoundException();
}
//通过byte[]数组得到Class
return defineClass(null, data, 0, data.length);
}
/**
* 从lib目录中得到字节码文件,并转成byte[]数组
* @param name
* @return
*/
private byte[] getClassData(String name) {
String classSrc = "lib" + File.separator + getClassName(name) + ".class";
try {
FileInputStream in = new FileInputStream(classSrc);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024*4];
int len = 0;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
return out.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
*
* @param classNamePath 形如:cn/zcl/lib/ClassLoaderDemo.class
* @return ClassLoaderDemo.class
*/
private String getClassName(String classNamePath) {
return classNamePath.substring(classNamePath.lastIndexOf(".") + 1);
}
}
其实实现类加载器只需继承ClassLoader,并覆写里面的findClass()方法。
最后测试一个测试类来测试我们写的类加载器是否成功
public class ClassLoaderTest2 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Date date = (Date)new CustomClassLoader().loadClass("cn.zcl.classLoaderDemo").newInstance();
System.out.println(date);
}
}
打印结果:
这是被类加载器加载的哦
这就表明我们写得自定义加载器已经成功。
下面总结下:
编写自定义的类加载器只需继承ClassLoader,并覆写里面的findClass()方法,将字节码文件转成Class实例,当然这里面使用到了defineClass()将字节数组转成Class实例。
扩展:
当在做开发中,出现类转换异常时,除了一般的转换外,还得注意是否一个类被两个类加载器加载,若一个类被两个类加载器加载,这两个字节码在内存中是不相等的,这点非常关键。
分享到:
相关推荐
类加载器是 Java 语言的一个创新,也是 ...不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试 ClassNotFoundException和 NoClassDefFoundError等异常。
Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射
该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...
自定义Java类加载器demo,自定义了一个classLoader,重写了loadClass 和findClass,注意 loadClass打破了双亲委派机制,所有的类都要在自定义的class文件中找到,而findClass遵循了双亲委派机制
Java类加载器机制与模型
本学习讲义是关于java类加载和反射机制需要注意的要点学习,内容详细
类加载器是 Java 语言的一个创新,也是 ...不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试 ClassNotFoundException和 NoClassDefFoundError等异常。
java类加载器和核心机制.pdf
此外,我们还会探讨Java程序的类加载器和双亲委派机制,以及自定义类加载器和类卸载的实现原理和应用方法。 总的来说,本资源将为Java程序员提供全面的Java字节码和类加载原理和实践经验。通过学习本资源,开发人员将...
对java的类加载机制,进行了深入的解析,并详细的实现了客户化加载器。
ClassLoader类加载器讲解,理解JAVA类加载机制
/** * java类加载器 * 类加载器负责加载与连接,这个过程是在运行时进行的,这种机制为java提供极大的灵活性 * * 类的生命周期 * class文件
jvm运行的过程中,需要载入类,而类的加载需要类加载器,本文章提供了java的类加载器的工作原理。可以使读者更加理解jvm的运行机制。
(1)双亲模型类加载器的作用:从class文件定义出class对象通过defineClass()方法进行定义类加载器 初始类加载器关系:该类的定义类加载器是该类
主要介绍了Java类加载器和类加载机制,结合实例形式分析了java类加载器与类加载机制原理、实现方法及相关操作技巧,需要的朋友可以参考下
学习概述:本模块深入讲解了Java类加载方面的知识,Java类加载器和类加载机制以及类加载原理 学习目标:掌握类加载机制和原理,能够独立开发自己的类加载器。 1.类的加载 什么是类加载? 类加载是指将类的...
他们提供的见解有助亍理解和解决常见的 Java 异常,例如 NoClassDefFoundError 和 ClassNotFoundException,以及更有挅戓性的问题,例如类装入器约束迗反和死锁。在第 1 部分中,他们详细描述了 Java 类装入的工作...
深入理解和探究Java类加载机制—- 1.java.lang.ClassLoader类介绍 java.lang.ClassLoader类的基本职责是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 ...
JAVA源码编译由三个过程组成: 1、源码编译机制。 2、类加载机制 ...系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类,当运行某个java程序时,会启动一个java虚拟机进程,两次运行
二、类的加载机制 在Java中,采用双亲委派机制来实现类的加载。那什么是双亲委派机制?在Java Doc中有这样一段描述: The ClassLoader class uses a delegation model to search for classes and resources