java文件编译成class文件之后,必须要放到java虚拟机才能执行,类的整个生命周期如下
第一步我们是进行加载,加载是由类加载器进行加载的,也就是说把clss文件变成字节流,然后放到虚拟机的一个过程,其中方法区放的是类信息,静态变量,常量,编译后的代码,同时在堆中生成一个代表该类的对象,作为方法区访问的入口
类加载器工作原理如下
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
1、首先检查这个类是否已经被加载,如果被加载过,返回该类的对象
2、如果没有被加载过,并且如果父加载器不为空,那么调用父加载器的loadClass方法加载类,如果父加载器为空,那么调用虚拟机的加载器(bootstrap classLoader)来加载类。
3、如果还没有成功的加载到类,那么就调用自己的findClass(name)来加载类
其实就是通过递归调用查找顶层父类去加载,如果都加载不了,才会交给自定义的类去加载,这就是双亲委派模式,也就是说有加载类请求的时候优先从父类加载,父类搜索不到该类的路径时,才会交由自定义的类加载器完成加载请求,这样做的目的是为了安全考虑,比如说用户自定义一个java.util.hashmap,但是由于这个类已经由启动类加载器加载了,这个时候自定义的这个路径是不会再重新加载一次了
验证阶段主要就是验证魔数,版本号,文件格式等
准备就是为类变量分配内存并设置初始值,解析就是将符号引用替换为直接引用的过程。