ClassLoader类加载器
类加载器的作用
类加载器用于加载编译生成的 *.class 文件内容(每一个类在编译之后都会生成一个.class文件)。
Java有以下几种类加载器:
Bootstrap(启动类加载器,C++实现):用于加载%JAVA_HOME%/lib目录下(或者被Xbootclasspath参数指定路径中)能被虚拟机识别的类库加载到JVM内存中,启动类加载器是由C++实现的,所以无法被Java程序直接引用。
ExtClassLoader(扩展类加载器,Java实现):用于加载%JAVA_HOME%/lib/ext目录下(或者被java.ext.dirs系统变量指定路径中的类库),他可以被Java程序调用。
AppClassLoader(应用程序类加载器):负责加载用户路径(ClassPath)上指定的类库,如果应用程序没有自定义自己的类加载器,AppClassLoader就是默认的类加载器
来看一段查看Java类加载器的代码
public class Test{
public static void main(String[] args) {
System.out.println("当前类的类加载器:" + Test.class.getClassLoader());
System.out.println(Test.class.getClassLoader().getParent());
System.out.println(Test.class.getClassLoader().getParent().getParent());
}
}
运行结果如下:
可见默认的类加载器是AppClassLoader。而且只可以看见AppClassLoader和ExtClassLoader,因为Bootstrap(启动类加载器是不能被Java程序直接调用的)。
双亲委派模型:
执行类加载的时候,并不会使用当前类加载器(默认的类加载器是AppClassLoader)。而是直接查看当前类加载器的父类加载器是否能加载,如果能加载,就让父类加载器加载,这一举动保证了Java程序的运行正常。
自定义类加载器
为什么要自定义类加载器?
(1)加密:众所周知,java代码很容易被反编译,如果你需要把自己的代码进行加密,可以先将编译后的代码用某种加密算法加密,然后实现自己的类加载器,负责将这段加密后的代码还原。
(2)从非标准的来源加载代码:由于存在的三个类加载器只能加载环境指定目录下的类。但是你的部分字节码(*.class文件)是放在数据库中甚至是网络上的,就可以自己写个类加载器,从指定的来源加载类。
(3)动态创建:为了性能等等可能的理由,根据实际情况动态创建代码并执行。
自定义类加载器的代码实现:
import java.io.*;
class MyClassLoader extends ClassLoader{
public Class<?> loadMyClass(String className) throws IOException{
FileInputStream fis = new FileInputStream("C:\\Users\\hasee\\Desktop\\testClassLoader\\Person.class");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int flag = 0;
while((flag = fis.read(b)) != -1) {
baos.write(b, 0, flag);
}
byte[] result = baos.toByteArray();
baos.close();
fis.close();
return defineClass(className, result, 0, result.length);
}
}
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IOException {
MyClassLoader myCls = new MyClassLoader();
Class<?> class1 = myCls.loadMyClass("Person");
System.out.println(class1.getClassLoader());
System.out.println(class1.getClassLoader().getParent());
System.out.println(class1.getClassLoader().getParent().getParent());
System.out.println(class1.getClassLoader().getParent().getParent().getParent());
System.out.println(class1.newInstance());
}
}
Person类:
public class Person{
public String toString(){
return "my class loader";
}
}
运行结果: