类加载过程
JVM会通过加载、连接、初始化3个步骤来对该类进行初始化
类加载器
类加载器可以分为4种:启动类加载器,拓展类加载器,应用类加载器,自定义类加载器
做个简单demo测试:
System.out.println(String.class.getClassLoader());
System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());//ext包下面的类
System.out.println(ClassLoaderTest1.class.getClassLoader());//本地测试类
null
sun.misc.Launcher$ExtClassLoader@60e53b93
sun.misc.Launcher$AppClassLoader@18b4aac2
第一个结果输出为什么是null?
- Bootstrap ClassLoader由C++实现,Java中找不到对应的类
JVM加载采用双亲委派机制,主要出于安全考虑。Loading的过程可以理解为:
findInCache --> parent.loadClass --> findClass
注:父加载器不是"类加载器的加载器",也不是"类加载器的父类加载器"!!!
System.out.println(ClassLoaderTest2.class.getClassLoader());
System.out.println(ClassLoaderTest2.class.getClassLoader().getClass().getClassLoader());
System.out.println(ClassLoaderTest2.class.getClassLoader().getParent().getClass().getClassLoader());
System.out.println(ClassLoaderTest2.class.getClassLoader().getParent());
sun.misc.Launcher$AppClassLoader@18b4aac2
null
null
sun.misc.Launcher$ExtClassLoader@6e0be858
自定义类加载器
为什么要用自定义类加载器?
- 我们需要的类不一定存放在已经设置好的ClassPath下,对于自定义路径中的class类文件的加载,我们需要自己的ClassLoader
- 有时我们可能是从网络的输入流中读取类,这就需要做一些加密和解密操作,这就需要自己实现加载类的逻辑,当然其他的特殊处理也同样适用
- 可以定义类的实现机制,实现类的热部署
怎样写一个自定义类加载器?源码比较简单,这里不再罗列
- 继承ClassLoader
- 重写findClass方法
- findClass方法调用defineClass方法(将byte[]类型的数据转换成Class)
具体实现如下:
public class HelloJVM {
public void hello() {
System.out.println("Hello JVM!");
}
}
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = loadClassData();
return super.defineClass(name, data, 0, data.length);
}
private byte[] loadClassData() {
InputStream is = null;
ByteArrayOutputStream baos = null;
byte[] data = null;
try {
is = new FileInputStream(new File("/****/HelloJVM.class"));
baos = new ByteArrayOutputStream();
int b = 0;
byte[] buffer = new byte[1024];
while ((b = is.read(buffer)) != -1) {
baos.write(buffer, 0, b);
}
data = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return data;
}
public static void main(String[] args) throws Exception {
CustomClassLoader classLoader = new CustomClassLoader();
Class<?> clazz = classLoader.loadClass("HelloJVM");
Object obj = clazz.newInstance();
clazz.getMethod("hello").invoke(obj);
System.out.println(clazz.getClassLoader());
}
}
执行结果: