1 编写一个类,该类继承Date类:
package erica.classloader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Date;
public class ClassLoaderAttachment extends Date {
@Override
public String toString() {
return "hello erica";
}
}
2 编写一个类,该类可以使得加载的class文件,生成的class文件放在D:\itunes
package erica.classloader;
import java.io.*;
public class MyClassLoader {
public static void cypher(InputStream in,OutputStream out) throws IOException{
int b=-1;
while((b=in.read())!=-1){
out.write(b^0xff);
}
}
}
3 运行生成加密以后的class
public static void main(String[] args) throws Exception {
String srcPath="D:/workspace/WorkSpaceSpring/ReflectTest/bin/erica/classloader/ClassLoaderAttachment.class";
String descPath="D:\\itunes\\ClassLoaderAttachment.class";
FileInputStream fis=new FileInputStream(srcPath);
FileOutputStream fos=new FileOutputStream(descPath);
cypher(fis,fos);
System.out.println("success");
}
4 把生成的class覆盖原始的那个类的class文件,然后用java虚拟机特定的classloader去加载文件会报错。
package erica.classloader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Date;
public class ClassLoaderAttachment extends Date {
@Override
public String toString() {
return "hello erica";
}
public static void main(String[] args) throws Exception {
ClassLoaderAttachment ca=new ClassLoaderAttachment();
System.out.println(ca);
}
}
报错如图所示:
5 那么就的我们自己的写的类加载器去加载加密的class了.
1:继承ClassLoader类
2:覆盖 protected Class<?>findClass(String name)throws ClassNotFoundException 方法
3:调用defineClass,将一个 byte 数组转换为 Class 类的实例,该实例就是加载一串二进制字节码的Class的对象
public class MyClassLoader extends ClassLoader{
private String dir;
public MyClassLoader(){
}
public MyClassLoader(String dir){
this.dir=dir;
}
@Override
protected Class<?>findClass(String name)throws ClassNotFoundException{
System.out.println("findClass");
String classname=dir+"/"+name+".class";
FileInputStream fis;
try {
fis = new FileInputStream(classname);
ByteArrayOutputStream out=new ByteArrayOutputStream();
cypher(fis,out);
fis.close();
byte[]bytes=out.toByteArray();
return defineClass(null,bytes,0,bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
6:用自己的类加载器加载自己的字节码
public static void main(String[] args) throws Exception {
MyClassLoader loader=new MyClassLoader("erica");
Date d=(Date)loader.loadClass("ClassLoaderAttachment").newInstance();
//Date d=(Date)loader.loadClass("erica.classloader.ClassLoaderAttachment").newInstance();//会去加载原始的class,因为指定了包名+类名
System.out.println(d);
}
打印结果:
findClass
hello erica
打印出findClass字符串说明运行了自己的类加载器。
下面是jdk文档的自己编写类加载器的示例:
例如,应用程序可以创建一个网络类加载器,从服务器中下载类文件。示例代码如下所示:
ClassLoader loader = new NetworkClassLoader(host, port); Object main = loader.loadClass("Main", true).newInstance(); . . .
网络类加载器子类必须定义方法 findClass
和 loadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法 defineClass
来创建类实例。示例实现如下:
class NetworkClassLoader extends ClassLoader { String host; int port; public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection . . . } }