操作流程都在代码注释中:
/**
* 自定义文件系统类加载器 ---->使用自定义类加载器加载 某一目录下的字节码
* @author
* 将d:/myjava/com/zm/HelloWorld.class 通过自定义类加载器加载
*
* 1 extends ClassLoader 重写findClass(String name)
* 2 findClass(String name)内先去findLoadedClass(name)中找 没找到在去parent.loadClass(name)找,在没找到则用自己的代码
* 写流获取目标文件的byte[]
* 3 根据 c = defineClass(name, classData, 0,classData.length);得到Class对象并返回即可
*
*/
public class FileSystemClassLoader extends ClassLoader {
// d:/myjava/
private String rootDir;
public FileSystemClassLoader(String rootDir){
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 先去加载器里面看看已经加载到的类中是否有这个类
Class<?> c = findLoadedClass(name); // loader.loadClass("com.zm.HelloWorld");
//应该要先查询有没有加载过这个类。如果已经加载,则直接返回加载好的类。如果没有,则加载新的类。
if(c!=null){
return c;
}else{
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); //委派给父类加载 调用JVM委托机制来加载,如果一层层上抛都没有加载到com.zm.HelloWorld的话 则走到46行 调用自己的类加载
} catch (Exception e) {
// e.printStackTrace();
}
if(c!=null){
return c;
}else{//
byte[] classData = getClassData(name);
if(classData==null){
throw new ClassNotFoundException();
}else{
// 将字节码处理成 Class实例返回
c = defineClass(name, classData, 0,classData.length);
}
}
}
return c;
}
// 读取流 将读到的流处理成字节码数组返回
private byte[] getClassData(String classname){ //com.zm.HelloWorld d:/myjava/ com/zm/HelloWorld.class
String path = rootDir +"/"+ classname.replace('.', '/')+".class";
// IOUtils,可以使用它将流中的数据转成字节数组
InputStream is = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try{
is = new FileInputStream(path);
byte[] buffer = new byte[1024];
int temp=0;
while((temp=is.read(buffer))!=-1){
baos.write(buffer, 0, temp);
}
return baos.toByteArray();
}catch(Exception e){
e.printStackTrace();
return null;
}finally{
try {
if(is!=null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(baos!=null){
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2
public class Demo03 {
public static void main(String[] args) throws Exception{
FileSystemClassLoader loader = new FileSystemClassLoader("d:/myjava");
FileSystemClassLoader loader2 = new FileSystemClassLoader("d:/myjava");
Class<?> c = loader.loadClass("com.zm.HelloWorld");
Class<?> c2 = loader.loadClass("com.zm.HelloWorldd");
Class<?> c3 = loader2.loadClass("com.zm.HelloWorld");
Class<?> c4 = loader2.loadClass("java.lang.String");
Class<?> c5 = loader2.loadClass("com.zm.HelloWorld");
System.out.println(c.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode()); //同一个类,被不同的加载器加载,JVM认为也是不相同的类
System.out.println(c4.hashCode());
System.out.println(c4.getClassLoader()); //引导类加载器
System.out.println(c3.getClassLoader()); //自定义的类加载器
System.out.println(c5.getClassLoader()); //系统默认的类加载器
}
}