类加载器(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实例。
扩展:
当在做开发中,出现类转换异常时,除了一般的转换外,还得注意是否一个类被两个类加载器加载,若一个类被两个类加载器加载,这两个字节码在内存中是不相等的,这点非常关键。
分享到:
相关推荐
这种机制有效地避免了子类加载器去重复加载已经被父类加载器加载过的类。 #### 五、不同类型的类加载器 根据类加载器的来源和作用范围,可以将其分为三种类型: 1. **启动类加载器(Bootstrap ClassLoader)** -...
Java 类加载器原理 Java 类加载器是Java虚拟机(JVM)的核心组成部分,它负责将类的字节码加载到内存中并转换为可执行的Java类。类加载器的作用不仅仅是加载类,还包括确保类的唯一性,避免重复加载,并且遵循特定...
### 深入研究Java类加载机制 #### 一、Java类加载机制概述 Java类加载机制是Java程序运行的第一步,它对于理解Java虚拟机(JVM)的行为至关重要。类加载过程涉及到类的加载、链接(验证、准备、解析)、初始化等...
类加载器是 Java 语言的一个创新,也是 ...不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试 ClassNotFoundException和 NoClassDefFoundError等异常。
Java 类加载器是Java运行时环境的一个重要组成部分,它的主要职责是将编译后的字节码(.class文件)加载到JVM中,使得程序能够运行。类加载器的机制保证了类的唯一性,同时也提供了灵活性,允许我们自定义加载逻辑。...
### Java类加载器详解 Java类加载器是Java运行时环境的一个关键组成部分,负责将类文件(.class)从各种来源加载到JVM中。它不仅管理类的生命...掌握类加载器的工作机制对于深入理解Java应用的运行时行为至关重要。
自定义Java类加载器允许我们根据特定需求扩展默认的加载机制,例如,从非标准位置加载类或者实现动态加载。在Java中,类加载过程分为加载、验证、准备、解析和初始化五个阶段。 首先,让我们了解Java中的默认类加载...
理解类加载器的工作原理对于深入掌握 Java 语言及其运行机制至关重要。本文将详细探讨 Java 类加载器的概念、类型以及工作流程。 类加载器是 Java 运行时环境中的核心组件,它们不仅负责类的加载,还维护了 Java ...
2. Webapp ClassLoader:每个Web应用程序都有自己的Webapp ClassLoader,用于加载WEB-INF/classes和WEB-INF/lib下的类,遵循"父子优先"原则,优先尝试从父类加载器加载,如果找不到再从自身加载。 3. Shared ...
在判断两个类是否相等时,必须确保这两个类是由同一个类加载器加载的,否则即使来源于同一个class文件,这两个类也被视为不相等。 ##### 3.1 双亲委派模型 双亲委派模型是Java类加载器的重要特性之一,它的基本...
Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射
即使两个类具有相同的名字和包名,但如果它们是由不同的类加载器加载的,那么这两个类就被认为是不同的。例如,两个类 `C1` 和 `C2` 都来自同一个包 `Pg`,但分别由类加载器 `kl1` 和 `kl2` 加载,那么在 JVM 中,...
总之,Java类加载器机制是Java平台灵活性和动态性的重要体现,它使得JVM能够在运行时加载和解析类,支持代码的热部署,增强了系统的可扩展性和可维护性。通过深入学习和理解这一机制,开发者能够更好地驾驭Java应用...
类加载器和类之间存在一对一的关系,不同的类加载器加载的同名类会被视为不同的类。这为Java的模块化和隔离提供了基础,例如,在Web应用服务器中,每个Web应用都有自己的类加载器,保证了不同应用之间的类隔离。 6...
该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...
Java 类加载机制是Java平台的核心特性之一,它负责将类的字节码加载到Java虚拟机(JVM)中并转换为运行时的类对象。理解这一机制对于优化应用程序性能和解决类相关的错误至关重要。 首先,类加载的过程分为三个主要...
而`log4j`的配置文件可能被不同的类加载器加载,这就需要我们理解类加载器如何查找和加载资源,以及在多层类加载器结构下如何配置和管理`log4j`。 设计模式在类加载器的设计中也扮演着重要角色。例如,使用工厂模式...
这种机制避免了类的重复加载,并且允许自定义类加载器覆盖父类加载器的行为。 线程上下文类加载器(Thread Context ClassLoader)是一个特殊的角色,它允许在多线程环境中控制类的加载。每个线程都有一个与之关联的...