java类加载全过程(二)

2014-11-24 10:14:26 · 作者: · 浏览: 1
施阶段就可以尝试用-Xverify:none参数来关闭大部分的类验证措施,以简短类加载时间。

接着就上面步骤完成后,就会进入准备阶段了:

这阶段会为类变量(指那些静态变量)分配内存并设置类比那辆初始值的阶段,这些内存在方法区中进行分配。这里要说明一下,这一步只会给那些静态变量设置一个初始的值,而那些实例变量是在实例化对象时进行分配的。这里的给类变量设初始值跟类变量的赋值有点不同,比如下面:

public static int value=123;

在这一阶段,value的值将会是0,而不是123,因为这个时候还没开始执行任何java代码,123还是不可见的,而我们所看到的把123赋值给value的putstatic指令是程序被编译后存在于(),所以,给value赋值为123是在初始化的时候才会执行的。

这里也有个例外:

public static final int value=123;

这里在准备阶段value的值就会初始化为123了。这个是说,在编译期,javac会为这个特殊的value生成一个ConstantValue属性,并在准备阶段jm就会根据这个ConstantValue的值来为value赋值了。

完成上步后,就要进行解析了。解析好像是对类的字段,方法等东西进行转换,具体涉及到Class文件的格式内容,并没深入去了解。

初始化过程是类加载过程的最后一步:

在前面的类加载过程中,除了在加载阶段用户可以通过自定义类加载器参与之外,其他的动作完全有jvm主导,到了初始化这块,才开始真正执行java里面的代码。

这一步将会执行一些预操作,注意区分在准备阶段,已经为类变量执行过一次系统赋值了。

其实说白了,这一步就是执行程序的();方法的过程。下面我们来研究一下()方法:

()方法叫做类构造器方法,有编译器自动手机类中的所有类变量的赋值动作和静态语句块中的语句合并而成的,置于他们的顺序与在源文件中排列的一样。

();方法与类构造方法不一样,他不需要显示得调用父类的();方法,虚拟机会保证子类的();方法在执行前父类的这个方法已经执行完毕了,也就是说,虚拟机中第一个被执行的();方法肯定是java.lang.Object类的。

下面来个例子说明一下:

[java]
static class Parent{
public static int A=1;
static{
A=2;
}
}
static class Sub extends Parent{
public static int B=A;
}
public static void main(String[] args){
System.out.println(Sub.B);
}


首先Sub.B中对静态数据进行了引用,Sub类要进行初始化了。同时,其父类Parent要先进行初始化动作。Parent初始化后,A=2,所以B=2;上个过程相当于:


[java]
static class Parent{
(){
public static int A=1;
static{
A=2;
}
}
}
static class Sub extends Parent{
(){ //jvm会先让父类的该方法执行完在执行这里
public static int B=A;
}
}
public static void main(String[] args){
System.out.println(Sub.B);
}


();方法对类跟接口来说不是必须的,假如类或者接口中没有对类变量进行赋值且没有静态代码块,()方法就不会被编译器生成。
由于接口里面不能存在static{}这种静态代码块,但仍然可能存在变量初始化时的变量赋值操作,所以接口里面也会生成()构造器。但跟类的不同的是,执行子接口的();方法前并不需要执行父接口的();方法,当父接口中定义的变量被使用时,父接口才会被初始化。

另外,接口的实现类在初始化的时候也一样不会执行接口的();方法。

另外,jvm会保证一个类的();方法在多线程环境下能被正确地加锁同步。<因为初始化只会被执行一次>。

下面用个例子说明一下:

[java]
public class DeadLoopClass {

static{
if(true){
System.out.println("要被 ["+Thread.currentThread()+"] 初始化了,下面来一个无限循环");
while(true){}
}
}

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("toplaile");
Runnable run=new Runnable(){

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("["+Thread.currentThread()+"] 要去实例化那个类了");
DeadLoopClass d=new DeadLoopClass();
System.out.println("["+Thread.currentThread()+"] 完成了那个类的初始化工作");

}}; www.2cto.com

new Thread(run).start();
new Thread(run).start();
}

}


这里面,运行的时候将会看到阻塞现象。

呼呼~先到这里`