1、class的执行过程
Class -> loading 将class文件放入内存
Verification : 校验 比如:.class文件前面的 cafebaba
Preparation:静态变量赋默认值.比如有一个char ch = ‘b’,这里加载的是 char ch=null
Resolution:class中常量池的符号引用转换为内存地址
Initializing: 初始化,初始化ch=’b’.
2、类加载器的介绍
这种图就是 class 执行过程中 Loading流程
现在我们看这段代码
public class Demo01 {
public static void main(String[] args) {
System.out.println(String.class.getClassLoader());
System.out.println(DNSNameService.class.getClassLoader());
System.out.println(Demo01.class.getClassLoader());
System.out.println(Demo01.class.getClassLoader().getParent());
System.out.println(Demo01.class.getClassLoader().getClass().getClassLoader());
}
}
null
sun.misc.Launcher$ExtClassLoader@12a3a380
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@12a3a380
null
Process finished with exit code 0
第 1 行因为加载的是bootstrap, 存在与c++,java里面找不到它
第 2 行说明这个类存在于 ExtClassLoader
第 3 行这里是我们写的类,所以返回的是AppClassLoader
第 4 行我们通过 getParent 拿到 AppClassLoader 的父级,所以返回 ExtClassLoader
第 5 行返回的事null,因为所有的ClassLoader上级都是Bootstrap 都会返回null出来
3、执行流程
现在我们大概找到了类加载器是什么了,那么我们看看 ClassLoader 是怎么加载的
1)首先class会来到自定义的ClassLoader中去寻找
2)如果找到则返回,没有找到那么我们往上走,也就是APP中寻找
3)一直找到Bootstrap还没有找到的情况下
4)Bootstrap 就会告诉 Extension ,这不属于我,你去创建
5)Extension 拿到这个class 后,如果这个class属于Extension ,那么创建,不属于再往下走
------- 这也就是传说中的 “ 双亲委派 ”
那么为什么要搞这么麻烦呢?
主要还是因为安全。
例子:
现在我们有一个java.lang.String类
如果说没有双亲委派机制,咋们是不是可以直接覆盖掉以前存在的String类
那么咋们后面要用String以前的东西都用不了了
现在有这个东西,String到Bootstrap的时候,我就返回了
4、流程源码
sun.boot.class.path Bootstrap ClassLoader 加载路径
java.ext.dirs ExtensionClassLoader 加载路径
java.class.path AppClassLoader 加载路径
loadClass 这里会进行判断,如果找到则返回,没有继续走流程
5、自定义ClassLoader
这里继承ClassLoaader,重写findClass方法
defineClass:转换成一个class对象放入内存
package com.fun;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import java.io.File;
import java.io.FileInputStream;
public class Demo03 extends ClassLoader{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
File f = new File("d:/aaa/untitled",name.replaceAll(".","/".concat(".class")));
try {
FileInputStream fs = new FileInputStream(f);
ByteOutputStream bos = new ByteOutputStream();
int i = 0;
while ((i = fs.read()) != 0){
bos.write(i);
}
byte[] bs = bos.getBytes();
bos.close();
fs.close();
return defineClass(name,bs,0,bs.length);
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
ClassLoader demo03 = new Demo03();
Class aClass = demo03.loadClass("com.fun.Demo02");
Demo02 demo02 = (Demo02)aClass.newInstance();
demo02.getName();
// 这里加载的其实还是 AppClassLoad,只是在 app 下重新 loadClass 了一下
System.out.println(demo03.getClass().getClassLoader());
System.out.println(demo03.getParent());
System.out.println(aClass.getClassLoader());
}
}