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 类
|
系统提供的类加载器
•引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自java.lang.ClassLoader。
•扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
•系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java类。一般来说,Java 应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。
三个加载器工作的目录
•这三个加载器就构成我们的Java类加载体系。他们分别从以下的路径寻找程序所需要的类:
•BootstrapLoader:sun.boot.class.path
•ExtClassLoader:java.ext.dirs
•AppClassLoader:java.class.path
•这三个系统参量可以通过System.getProperty()函数得到具体对应的路径。
public class ClassLoaderPathTest {
public static void main(String args[]) {
try{
System.out.println("BootstrapLoader's Load path sun.boot.class.path="+
System.getProperty("sun.boot.class.path"));
System.out.println("ExtClassLoader's Load path java.ext.dirs="+
System.getProperty("java.ext.dirs"));
System.out.println("BootstrapLoader's Load path java.class.path="+
System.getProperty("java.class.path"));
}catch(Exception e){
e.printStackTrace();
}
}
}
类加载器的树状组织结构
•有些 JDK 的实现对于父类加载器是引导类加载器的情况,getParent()方法返回null
类加载器的代理模式
•类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。
•Java虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。
•代理模式是为了保证 Java 核心库的类型安全。通过代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。
加载类的过程
•真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用defineClass来实现的;而启动类的加载过程是通过调用loadClass来实现的。前者称为一个类的定义加载器(defining loader),后者称为初始加载器(initiating loader)。在Java 虚拟机判断两个类是否相同的时候,使用的是类的定义加载器。也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。两种类加载器的关联之处在于:一个类的定义加载器是它引用的其它类的初始加载器。如类com.example.Outer引用了类com.example.Inner,则由类com.example.Outer的定义加载器负责启动类com.example.Inner的加载过程。
开发自己的类加载器
•一般来说,自己开发的类加载器只需要覆写findClass(String name)方法即可。java.lang.ClassLoader类的方法loadClass()封装了前面提到的代理模式的实现。该方法会首先调用findLoadedClass()方法来检查该类是否已经被加载过;如果没有加载过的话,会调用父类加载器的loadClass()方法来尝试加载该类;如果父类加载器无法加载该类的话,就调用findClass()方法来查找该类。因此,为了保证类加载器都正确实现代理模式,在开发自己的类加载器时,最好不要覆写loadClass()方法,而是覆写findClass()方法。
自定义类加载器代码示例:
package classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
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";
}
}
分享到:
相关推荐
深入探讨 Java 类加载器.wps深入探讨 Java 类加载器.wps深入探讨 Java 类加载器.wps
### 深入探讨Java类加载器 #### 类加载器基本概念 类加载器(Class Loader)是Java语言的关键组成部分之一,它负责将Java类的字节码加载到Java虚拟机(JVM)中,从而使得Java应用程序能够运行起来。自Java诞生以来...
下面我们将深入探讨Java类加载器以及Tomcat中的类加载器。 在Java中,类加载器主要分为三个层次:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader。Bootstrap ClassLoader负责加载JDK的核心库,如rt...
本文深入探讨了 Java 类加载器的概念、类型、工作机制以及如何实现自定义类加载器。通过理解类加载器,开发者可以更好地控制类的加载过程,提高应用的性能和安全性。希望本文能帮助你更深入地理解 Java 类加载器及其...
这篇文章将深入探讨 Java 类加载器中的静态变量初始化机制,了解其背后的工作原理和载入过程。 静态变量初始化机制 ------------------ 在 Java 中,静态变量是指在类加载时初始化的变量。静态变量的初始化是由类...
本文将深入探讨类加载器的工作原理,主要类加载器类型,并通过示例展示如何自定义类加载器。 首先,理解类与数据的区别是重要的。类是代码的蓝图,包含方法和字段声明,而数据则是这些类实例的运行时状态。每个类都...
在本篇文章中,我们将深入探讨Java类加载器的工作原理,以及其在代码执行中的作用。 首先,我们从基础开始。Java类加载器分为三个主要类型:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader。...
下面将详细探讨类加载器的工作原理、层次结构以及自定义类加载器的应用。 1. **类加载的生命周期** 类加载的过程包括加载、验证、准备、解析和初始化五个阶段。加载是将类的二进制数据读取到内存中;验证确保类的...
本部分我们将深入探讨JVM中的类加载器,特别是根类加载器、扩展类加载器和系统类加载器。 首先,让我们了解类加载的基本过程。当JVM启动时,会触发类加载。这个过程分为三个阶段:加载、链接和初始化。加载阶段,类...
在深入探讨Java类加载器(ClassLoader)之前,我们首先需要了解它在Java运行时系统中的核心作用。类加载器是Java虚拟机(JVM)的一个关键组成部分,负责查找、加载和链接类文件到JVM中。它的存在使得Java应用程序...
本文旨在深入探讨Java类加载的过程、原理及其在实际开发中的应用。 #### 二、类与数据的概念 在Java中,一个类定义了对象的行为与状态。类定义了可执行的代码,而数据则代表了对象的状态。状态是可以变化的,但...
本文将深入探讨Java类加载的各个方面。 首先,类的生命周期包括加载、验证、准备、解析和初始化五个阶段。加载阶段,JVM通过全限定类名获取二进制字节流,将其转换为方法区的运行时数据结构,并创建一个代表该类的...
本文将深入探讨"springboot+java类热加载"这一主题,包括其核心概念、实现方式以及相关技术。 **热加载(Hot Loading)**是开发过程中的一个重要功能,它允许开发者在不重启应用的情况下更新代码,提高开发效率。在...
在Java编程中,静态代码块(Static Block)和类加载器(Class Loader)是两个重要的概念,它们在软件开发中有着广泛的应用。本案例聚焦于如何利用静态代码块结合类加载器来高效地获取资源文件,尤其是属性配置文件。...
本文将基于"java经验积累"这一主题,深入探讨Java的相关知识点,包括类加载器、并发处理、注解(Annotation)、线程池、泛型、自定义注解以及Java与模式思考。 首先,我们来关注"深入探讨 Java 类加载器"。Java的类...
本文将深入探讨Java类加载的原理、过程以及相关知识点。 首先,我们需要理解类加载的三个基本阶段:加载、验证、准备、解析和初始化。在加载阶段,类加载器寻找指定的类文件,并将其内容读入内存。验证阶段确保字节...
本文将深入探讨 Java 类加载机制的核心概念和技术细节,帮助开发者更好地理解 Java 类加载的过程,以及如何利用这一机制解决实际问题。 #### 二、类和数据的关系 在 Java 中,类和数据有着密切的关系。类定义了...
本文将深入探讨Java类加载器的层次结构、工作原理以及如何实现动态加载类。 首先,Java类加载器分为系统类加载器和自定义类加载器。系统类加载器包括引导类加载器、扩展类加载器和系统类加载器: 1. 引导类加载器...
本篇文章将深入探讨如何实现自定义类加载器以及其背后的原理。 1. **类加载器的工作原理** - 类加载过程分为三个阶段:加载、验证、准备、解析和初始化。在加载阶段,类加载器寻找并加载类的二进制数据。 - Java...