Class Cycle 类的生命周期
Loading:把二进制的class文件load到内存中,会产生两块内容,一个是将class放到内存中,二是创建一个类对象指向这一块内存
Linking:
- verification:检查class文件的开头是不是CAFEBABE(标志),是否符合JVM的规定
- preparation:静态变量赋默认值,如int类型的值为0
- resolution:将类、方法、属性等符号引用解析为直接引用。常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用
Initializing:调用类初始化代码 <clinit>,给静态成员变量赋初始值
public class T001_ClassLoadingProcedure { public static void main(String[] args) { System.out.println(T.count); } } class T { public static T t = new T(); // null public static int count = 2; //0 private T() { count ++; //System.out.println("--" + count); } }
初始化T class 给静态成员变量赋默认值t=null、count=0,initializing给成员变量赋初始值t=new T()调用方法T()使count变为1,count初始化又变为2,把new T()和count=2调换的话,count的最终值为3
类加载器
不同的类由不同的类加载器进行装载,由jvm进行动态加载,采用双亲委派机制。
双亲委派
- 双亲委派的原因:防止自定义的Java类与jdk的类一样在加载是替代了JDK提供的类,如自定义一个名为java.lang.object类在加载是代替原来的类,那样就可以在自定义的类里面动手脚
- 双亲委派:加载一个类时先去向上看一下父加载器是否加载过了,一直往上知道没有父加载器,Bootstrap加载器发现自己没有加载过,再看自己是否可以加载这个类,可以的话就返回,不能就向下看子加载器是否可以加载。
- 直到最后都没有能加载这个类的加载器就抛出classNotFoundException异常
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
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
自定义类加载器
继承ClassLoader,重写findClass->defineClass(byte[] -> Class clazz)