在MyEclipse中编辑代码时,一旦保存,便会将源代码编译成class文件。
package com.interview.classLoader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
/**
* 自定义类加载器,加密并加载class文件
* @author dhh
* 继承ClassLoader:
* 使用方法 getSystemClassLoader() 返回的 ClassLoader 创建一个新的类加载器,将该加载器作为父类加载器。
* 那么MyClassLoader2就为系统类加载器的一个子类,会继承loadClass实现委托机制(即抛给上级类加载器加载)
*/
public class MyClassLoader2 extends ClassLoader{
//路径名
public String destDir = null;
//构造方法
public MyClassLoader2(){}
public MyClassLoader2(String destDir){
this.destDir = destDir;
}
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception{
//可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类
/**
* JDK API:
* loadClass使用指定的二进制名称来加载类。此方法的默认实现将按以下顺序搜索类:
* 1、调用 findLoadedClass(String) 来检查是否已经加载类。
* 2、在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。
* 3、调用 findClass(String) 方法查找类。
* 因此写自定义类加载器要重写findClass(String)方法
*
* 分析:
* 调用MyClassLoader2加载器,它会调用父类的loadClass,以此类推,BootStrap,ExtClassLoader调用findClass(String)都没有找到
* 轮到AppClassLoader,如果路径loadClass("com.interview.classLoader.enPackage"),可以找到类
* 如果将类替换成加密的class,可能会加载错误.
* 如果还是删除了com.interview.classLoader包中的enpackage.class,父类都找不到
* 就到了自定义的类加载器findLoad方法来加载,所以在这个方法中还要定义解密
* 才能得到正确的class
*/
Class clazz = new MyClassLoader2("myclass").loadClass("enPackage");
//类enPackage在加密的时候是实现了父类Date的,不过这是为什么呢?
//因为编译器无法确定加密后的enPackage,所以会报错
//所以用enPackage继承的父类Date来创建,这样编译器能够识别
Date myclazz = (Date)clazz.newInstance();
System.out.println(myclazz); //改写了toString()方法
}
@SuppressWarnings("deprecation")
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
InputStream input = null;
ByteArrayOutputStream output = null;
//相对项目的完整路径
String className = destDir + "\\" + name +".class";
try {
input = new FileInputStream(className);
output = new ByteArrayOutputStream();
enCode(input,output); //解密
return defineClass(output.toByteArray(), 0, output.toByteArray().length);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
input.close();
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 简单加密解密算法
* @param input
* @param output
*/
public void enCode(InputStream input,OutputStream output) throws Exception{
int len = 0 ;
while((len=input.read())!=-1){
output.write(len^ 0xff);
}
}
}