自定义类的加载器

it2024-03-30  49

一、目标

通过自定义加载器动态加载一个本地.class类文件,得到该类的class对象

二、代码分析

package com.lyz.classloader; import java.io.*; public class FileClassLoader extends ClassLoader { private String rootPath; public FileClassLoader(String rootPath) { this.rootPath = rootPath; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { //查看名为“name”的类是否被加载 Class<?> aClass = this.findLoadedClass(name); if(aClass == null) { try { //双亲委派机制 aClass = this.getParent().loadClass(name); } catch (ClassNotFoundException e) { //异常可以忽略 //e.printStackTrace(); } if(aClass == null) { byte[] buffer = getClassData(name); aClass = defineClass(name, buffer, 0, buffer.length); } else { return aClass; } } else { return aClass; } return aClass; } private byte[] getClassData(String name) { String pathClass = rootPath +File.separator+ name.replace(".",File.separator)+".class"; InputStream inputStream = null; ByteArrayOutputStream baos = null; try { inputStream = new FileInputStream(pathClass); baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while((len=inputStream.read(buffer))!=-1) { baos.write(buffer, 0, len); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } finally { try { if (inputStream!=null) inputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { if(baos!=null) baos.close(); } catch (IOException e) { e.printStackTrace(); } } } }

2.1为什么要使用ByteArrayOutputStream流

下面解释以下getClassData方法中为什么要用到ByteArrayOutputStream流,因为数组在定义的时候就必须确定长度,而我们如果不使用ByteArrayOutputStream流的toByteArray方法,就无法返回一个长度恰好等于.class文件的字节数组。

2.2 四个方法loadClass,findClass,findloadClass,defineClass

2.2.1findloadClass(String name)方法

查找已加载过的名为name(注:带包的全类名)的类,返回对应的class对象

2.2.2findClass(String name)方法

查找名为name的类,返回对应class对象

2.2.3defineClass(String name,byte[] b,int off,int len)

把字节数组b中的内容转换为java类,返回的结果是对应的class对象。name是全类名,b是已经编译好的.class文件转换成的字节数组,off与len限定了读入的字节数组长度

2.2.4loadClass(String name)

加载名为name的类,此方法定义在ClassLoader类中,采用了双亲委托机制,首先在已加载的类中寻找,然后Bootstrap ClassLoader中,再Extension ClassLoader,再Application ClassLoader,最后才是自定义的加载器 ,若要改变加载顺序,则重写此方法,但是不建议。

三、测试

package com.lyz.classloader; public class Text { public static void main(String[] args) { FileClassLoader fcl = new FileClassLoader("f:"); Class<?> aClass1 = null; try { aClass1 = fcl.loadClass("com.lyzh.Text"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(aClass1.hashCode()); System.out.println(aClass1.getClassLoader()); } }

注意,运行程序之前,在路径"F:\com\lyzh"下已经存在Text.class文件 带包的Text类编译时,javac -d . Text.class,“.”表示当前路径

最新回复(0)