准备两个目标:为已经在方法区的类的静态变量分配内存,为静态变量设置初始值。不同数据类型的初始默认值如下:casepublicstaticfinalintvalue=123;准备阶段后value的值为0,不是123,初始化后为123。但是如果是final修饰的,如果有初始值,编译阶段会把初始值存入constantValue属性,准备阶段会把constantValue的值赋给这个字段(赋值到123)。Resolution将常量池中的符号引用转换为直接引用。符号是指一组明确的符号来描述引用的目标。它与JVM的实现无关。直接引用直接指向目标的指针,相对偏移量,或者可以间接定位目标的句柄。它与JVM实现有关。主要为:类、接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符。初始化实际上开始执行类中定义的Java程序代码(或字节码)。类的初始化就是给类的静态变量赋初值,初始化阶段就是执行类构造函数的过程。如果该类还没有被加载和链接,它会先被执行。如果类有父类,而父类还没有初始化,则先初始化父类。如果类中有初始化语句,这些语句会依次执行。如果接口初始化了一个类,而当一个接口被初始化时,它的父接口并没有被初始化。只有当程序第一次使用接口中的变量或调用接口方法时,才会导致接口的初始化调用Classloader类的loadClass方法加载一个类,而不会初始化类,这不是主动使用该类的clinit()方法。由编译器自动生成,收集类中静态代码块中的类变量赋值语句和类中静态变量的赋值语句:在准备阶段,类中的静态变量已经默认初始化,在初始化阶段,clinit()方法变量被显式初始化类初始化的时机Java程序通过以下方式使用类:主动使用被动使用JVM必须在“第一次主动使用”时初始化每个类或接口.被动使用类不会导致类初始化。主动使用的场景创建一个类实例来访问某个类或接口的静态变量。如果是final常量,编译阶段常量会在常量池中,并没有引用定义常量的类,所以不会触发常量类的定义。初始化调用类的静态方法反映一个类初始化一个类的子类,但是父类还没有初始化JVM启动时运行的主类(等于第三项)定义了默认的接口方法,接口实现类初始化时FAQclinit()方法是IDE自动收集类中所有类变量的赋值动作和静态语句块中的语句生成的。IDE收集的顺序由语句在源文件中出现的顺序决定。静态代码块只能访问出现在静态代码块之前的变量,它后面定义的变量,可以在前面的静态语句块中赋值,但是不能访问publicclassTest{static{i=0;System.out.println(i);//CompileFailed:"Illegalforwardreference"}staticinti=1;}实例构造函数init()需要显式调用父类构造函数,而类的clinit()不需要调用父类的类构造函数。JVM会确保在子类的clinit()方法执行之前,父类的clinit()已经执行完毕。因此,在JVM中执行的clinit()方法的第一个类必须是java.lang.Object。如果一个类/接口既没有静态代码块,也没有静态成员变量的赋值操作,编译器就不会为这个类生成clinit()方法。接口还需要通过clinit()方法显式初始化接口中定义的静态成员变量。接口中不能使用静态代码块,但是变量初始化仍然有赋值操作,所以接口和类一样,会生成clinit()方法。不同的是:接口的clinit()方法不需要先执行父接口的clinit()方法,父接口的clinit()方法只有在parent中的静态成员变量时才会执行接口被使用。JVM将确保类的clinit()方法在多线程环境中被正确锁定和同步。当多个线程同时初始化一个类时,只有一个线程会执行该类的clinit()方法,其他线程会被阻塞等待,直到活跃线程执行完clinit()方法。虽然其他线程会被阻塞,但是只要执行了一个clinit()方法,其他线程醒来后就不会再进入clinit()方法了。在同一个类加载器下,一个类型只会被初始化一次。类卸载当代表一个类的Class对象不再被引用时,那么这个Class对象的生命周期就结束了,相应的方法区中的数据也会被卸载。Jvm自带的类加载器加载的类不会被卸载,自定义类加载器加载的类可以被卸载。
