大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
我们可以编写自己的用于特殊目的的类加载器,这使得我们可以在向虚拟机传递字节码之前执行定制的检查。
如何自定义类加载器
如果想要编写自己的类加载器,只需要两步:
继承ClassLoader类
覆盖findClass(String className)方法
ClassLoader超类的loadClass方法用于将类的加载操作委托给其父类加载器去进行,只有当该类尚未加载并且父类加载器也无法加载该类时,才调用findClass方法。
如果要实现该方法,必须做到以下几点:
1.为来自本地文件系统或者其他来源的类加载其字节码。
2.调用ClassLoader超类的defineClass方法,向虚拟机提供字节码。
下面是自定义类加载器的一种实现方式:
public class CustomClassLoader extends ClassLoader {
protected Class> findClass(String name) throws ClassNotFoundException {
try {
String cname = “/Users/wuzhenyu/Desktop/spring-boot/src/main/java/” + name.replace(‘.’, ‘/’) + “.class”;
byte[] classBytes = Files.readAllBytes(Paths.get(cname));
Class> cl = defineClass(name, classBytes, 0, classBytes.length);
if (cl == null) {
throw new ClassNotFoundException(name);
}
return cl;
} catch (IOException e) {
System.out.print(e);
throw new ClassNotFoundException(name);
}
}
}
我在该类的目录下准备了一个编译好的类文件SayHello.class(后缀改为了text),SayHello.class对应的Java代码如下:
public class SayHello {
public static void main(String[] args) {
System.out.print(“Hello World”);
}
}
下面是测试类的代码:
测试前请删除SayHello.java文件
public class ClassLoaderTest {
public static void main(String[] args) {
try {
ClassLoader loader = new CustomClassLoader();
//调用loadClass加载sample.loader.SayHello类
//无法加载到该类,因此会调用findClass方法
Class> c = loader.loadClass(“sample.loader.SayHello”);
Method m = c.getMethod(“main”, String[].class);
m.invoke(null, (Object) new String[]{});
} catch (Throwable e) {
System.out.println(e);
}
}
}
运行结果如下:
Hello World
这是一个简单的实现自己类加载器的例子。在更复杂的案例中,使用的往往是加密过的类文件,加载该类字节码时,还需要解密。不然它们就不能由标准虚拟机来执行,也不能轻易被反汇编。
类加载器相关的API
1. java.lang.Class
ClassLoader getClassLoader(): 获取加载该类的类加载器
2.java.lang.ClassLoader
ClassLoader getParent():返回父类加载器,如果父类加载器是引导类加载器,则返回null。
static ClassLoader getSystemClassLoader():获取系统类加载器,即用于加载第一个应用类的类加载器。
protected Class findClass(String name):类加载器应该覆盖该方法,以查找类的字节码,并通过调用defineClass方法将字节码传给虚拟机。在类的名字中,使用.作为包名分隔符,并且不使用.class后缀。
Class definedClass(String name, byte[] byteCodeData, int offset, int length):将一个新的类添加到虚拟机,其字节码在给定的数据范围中。
3.java.net.URLClassLoader
URLClassLoader(URL[] urls)
URLClassLoader(URL[] urls, ClassLoader parent) :构建一个类加载器,它可以从给定的URL处加载类。如果URL以 / 结尾,那么它表示的一个目录,否则,它表示的是一个JAR文件。
4.java.lang.Thread
ClassLoader getContextClassLoader():获取类加载器,该线程的创建者将其指定为执行该线程时最适合使用的类加载器。
void setContextClassLoader(ClassLoader loader):为该线程中的代码设置一个类加载器,以获取要加载的类。如果在启动一个线程时没有显式地设置上下文类加载器,则使用父线程的上下文类加载器。
参考文献《Java 核心技术 卷二》
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/196723.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...