之前一直在想如何读取一个class文件,并且获取其中的信息,Java有自己的_ClassLoader_ ,可以加载系统需要的class文件,或者用户自定义的class文件,但是对目录要求较高,需要时在classpath下,但是能不能将任意位置的class文件加载呢。
class文件是以二进制流的方式存在磁盘文件上的,ClassLoader也肯定是在二进制文流读到内存中去的。终于找到在ClassLoader类中存在一个
defineClass(String name, byte[]b,int off,int len);
方法,
其中: String name 指的是类名,是一个完整的带包名的类名,如果不知道,可以使用 null
byte []b 就是class文件的字节流 ,关键的东东啊
int off 也就是起始位置 , len 读取的字节长度了,很好理解啊
因为defineClass 是受保护的方法,不能直接访问,那么我们写一个方法继承自ClassLoader 是不是就 OK了呢?
实现步骤:
自定义Loader
package com.jokingus.cls;
import java.io.FileInputStream;
public class Loader extends ClassLoader{
static int maxsize=10000;
public Class<?> load(String namefile,String className) throws Exception{
Class<?> ctmp= this.findLoadedClass(className);
//查看class是否已经被加载了
if(ctmp!=null){
System.out.println("class文件已经被加载了");
return ctmp;
}
FileInputStream in=new FileInputStream(namefile);
byte[] classbyte=new byte[maxsize];
int readsize;
readsize=in.read(classbyte);
System.out.println("readsize:"+readsize);
in.close();
return defineClass(null, classbyte, 0,readsize);
}
}
测试代码:
package com.jokingus.cls;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public void parseMethod(Class<?> cls) {
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
System.out.println(Modifier.toString(m.getModifiers()));
Class<?> returnType = m.getReturnType();
System.out.println(returnType.getName());
Class<?>[] parameterTypes = m.getParameterTypes();
for (Class<?> clas : parameterTypes) {
String parameterName = clas.getName();
System.out.println("参数名称:" + parameterName);
}
System.out.println(m.getName());
System.out.println("\n****************");
}
}
public void parseDeclaration(Class<?> cls) {
Field[] fields = cls.getDeclaredFields();
for (Field f : fields) {
System.out.print(Modifier.toString(f.getModifiers()) + " ");
System.out.print(f.getGenericType().toString() + " ");
System.out.print(f.getName() + " = ");
try {
f.setAccessible(true);
System.out.println(f.get(f.getGenericType()));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println();
}
}
public void parseAnnotation(Class<?> cls) {
Annotation[] annos = cls.getAnnotations();
for (Annotation anno : annos) {
System.out.println(anno.toString());
Class<?> types = anno.annotationType();
System.out.println(types.getName());
}
}
public static void main(String[] args) throws Exception {
Test t = new Test();
Loader loader = new Loader();
String namefile = "E:/Eclipse/IO/bin/com/wang/bytemodel/FileDemo.class";
namefile = "E:/wangming/maven/high/target/classes/com/jokingus/dbutils/DBPool.class";
namefile = "E:/wangming/maven/high/target/classes/com/jokingus/anno/SayHello.class";
Class<?> c = loader.load(namefile, null);
System.out.println(c.getName());
String className = c.getName();
// t.parseMethod(c);
System.out.println("--------------------------------------");
t.parseDeclaration(c);
System.out.println("--------------------------------------");
t.parseAnnotation(c);
// loader.load(namefile,className);
}
}
保证namefile 为你的电脑上实际存在的一个 class文件,只要路径不错,应该就没有什么问题了。
祝成功!!!