Java实现的自定义类加载器示例
本文实例讲述了Java实现的自定义类加载器。分享给大家供大家参考,具体如下:
一点睛
1ClassLoader类有如下两个关键方法:
loadClass(Stringname,booleanresolve):该方法为ClassLoader的入口点,根据指定的二进制名称来加载类,系统就是调用ClassLoader的该方法来获取指定类对应的Class对象。
findClass(Stringname):根据二进制名称来查找类。
如果需要实现自定义的ClassLoader,可以通过重写以上两个方法来实现,当然我们推荐重写findClass()方法,而不是重写loadClass()方法。
2自定义类加载器常用功能
执行代码前自动验证数字签名。
根据用户提供的密码解密代码,从而可以实现代码混淆器来避免反编译class文件。
根据用户需求来动态地加载类。
根据应用需求把其他数据以字节码的形式加载到应用中。
二实战
1CompileClassLoader.java
importjava.io.*;
importjava.lang.reflect.*;
publicclassCompileClassLoaderextendsClassLoader
{
//读取一个文件的内容
privatebyte[]getBytes(Stringfilename)
throwsIOException
{
Filefile=newFile(filename);
longlen=file.length();
byte[]raw=newbyte[(int)len];
try(
FileInputStreamfin=newFileInputStream(file))
{
//一次读取class文件的全部二进制数据
intr=fin.read(raw);
if(r!=len)
thrownewIOException("无法读取全部文件:"
+r+"!="+len);
returnraw;
}
}
//定义编译指定Java文件的方法
privatebooleancompile(StringjavaFile)
throwsIOException
{
System.out.println("CompileClassLoader:正在编译"
+javaFile+"...");
//调用系统的javac命令
Processp=Runtime.getRuntime().exec("javac"+javaFile);
try
{
//其他线程都等待这个线程完成
p.waitFor();
}
catch(InterruptedExceptionie)
{
System.out.println(ie);
}
//获取javac线程的退出值
intret=p.exitValue();
//返回编译是否成功
returnret==0;
}
//重写ClassLoader的findClass方法
protectedClass>findClass(Stringname)
throwsClassNotFoundException
{
Classclazz=null;
//将包路径中的点(.)替换成斜线(/)。
StringfileStub=name.replace(".","/");
StringjavaFilename=fileStub+".java";
StringclassFilename=fileStub+".class";
FilejavaFile=newFile(javaFilename);
FileclassFile=newFile(classFilename);
//当指定Java源文件存在,且class文件不存在、或者Java源文件
//的修改时间比class文件修改时间更晚,重新编译
if(javaFile.exists()&&(!classFile.exists()
||javaFile.lastModified()>classFile.lastModified()))
{
try
{
//如果编译失败,或者该Class文件不存在
if(!compile(javaFilename)||!classFile.exists())
{
thrownewClassNotFoundException(
"ClassNotFoundExcetpion:"+javaFilename);
}
}
catch(IOExceptionex)
{
ex.printStackTrace();
}
}
//如果class文件存在,系统负责将该文件转换成Class对象
if(classFile.exists())
{
try
{
//将class文件的二进制数据读入数组
byte[]raw=getBytes(classFilename);
//调用ClassLoader的defineClass方法将二进制数据转换成Class对象
clazz=defineClass(name,raw,0,raw.length);
}
catch(IOExceptionie)
{
ie.printStackTrace();
}
}
//如果clazz为null,表明加载失败,则抛出异常
if(clazz==null)
{
thrownewClassNotFoundException(name);
}
returnclazz;
}
//定义一个主方法
publicstaticvoidmain(String[]args)throwsException
{
//如果运行该程序时没有参数,即没有目标类
if(args.length<1)
{
System.out.println("缺少目标类,请按如下格式运行Java源文件:");
System.out.println("javaCompileClassLoaderClassName");
}
//第一个参数是需要运行的类
StringprogClass=args[0];
//剩下的参数将作为运行目标类时的参数,
//将这些参数复制到一个新数组中
String[]progArgs=newString[args.length-1];
System.arraycopy(args,1,progArgs
,0,progArgs.length);
CompileClassLoaderccl=newCompileClassLoader();
//加载需要运行的类
Class>clazz=ccl.loadClass(progClass);
//获取需要运行的类的主方法
Methodmain=clazz.getMethod("main",(newString[0]).getClass());
Object[]argsArray={progArgs};
main.invoke(null,argsArray);
}
}
2Hello.java
publicclassHello
{
publicstaticvoidmain(String[]args)
{
for(Stringarg:args)
{
System.out.println("运行Hello的参数:"+arg);
}
}
}
3运行
E:\Java\疯狂java讲义\codes\18\18.2>javaCompileClassLoaderHello自定义加载器
CompileClassLoader:正在编译Hello.java...
运行Hello的参数:自定义加载器
更多java相关内容感兴趣的读者可查看本站专题:《Java面向对象程序设计入门与进阶教程》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》
希望本文所述对大家java程序设计有所帮助。