类加载器ClassLoader是用来将java的类加载到虚拟机中,类加载器负责读取class字节文件到内存中,并将它转为Class的对象(类对象),通过此实例的 newInstance()
方法就可以创建出该类的一个对象。
其中重要的方法为findClass(String name)。
如何写一个自己的类加载器呢?
首先写一个便于测试的类Student
有一个属性和一个方法
package 类的加载;
public class Student {
int x;
public void setX(int x) {
this.x = x;
System.out.println(x);
}
}
写一个自己的类加载器。就是读取class文件,并将其实例化为Class对象的一个过程。
但是必须注意,同一个类如果用不同的加载器对其进行多次加载,会产生异常。所以一旦有一个加载器加载过了就不用再进行加载。
public class MyClassLoder extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class c = findLoadedClass(name);
// 保证加载的唯一性,如果之前已经被加载过了,就不用再加载了。
if (c == null) {
byte data[] = readFile(name);
c = this.defineClass(data, 0, data.length);
this.resolveClass(c);// 将对象c交给虚拟机去管理
System.out.println("加载好了");
}
return c;
}
/**
* 读取指定的class文件的字节数据
*
* @param name
* @return
*/
public byte[] readFile(String name) {
byte[] bt = null;
String path = "bin/" + name.replace(".", "/") + ".class";
System.out.println(path);
try {
FileInputStream fis = new FileInputStream(new File(path));
// // 但是无法确定你会读到多少数据
// byte bt[] = new byte[100];
// fis.read(bt);
// 用字节数组流临时存储数据,可以不管其长度
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int t = fis.read();
while (t != -1) {
baos.write(t);
t = fis.read();
}
bt = baos.toByteArray();
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
return bt;
}
}
创建一个加载器
MyClassLoder mcl = new MyClassLoder();
得到这个类
Class c = mcl.findClass("类的加载.Student");
同样,进行方法的测试
Method m = c.getMethod("setX", int.class);
Constructor cs = c.getConstructor();
Object obj = cs.newInstance();
m.invoke(obj, 1);
输出结果为
bin/类的加载/Student.class
加载好了
1
在下面再加一个:
Class c2 = mcl.findClass("类的加载.Student");
Method m2 = c2.getMethod("setX", int.class);
Constructor cs2 = c.getConstructor();
Object obj2 = cs2.newInstance();
m2.invoke(obj2, 1);
System.out.println(c==c2);
输出结果为
bin/类的加载/Student.class
加载好了
1
1
true
可以发现都是同一个类
Class c3 = Class.forName("类的加载.Student");
System.out.println(c);
System.out.println(c3);
Constructor cs3 = c3.getConstructor();
Object obj3 = cs3.newInstance();
System.out.println((Student)obj2);
输出结果为:
class 类的加载.Student
class 类的加载.Student
java.lang.ClassCastException: 类的加载.Student cannot be cast to 类的加载.Student
at 类的加载.Test.main(Test.java:33)
也就是说不能重复对其加载。