JVM虚拟机如何来初始化构造方法的


面先说一下环境,比如现在有两个类,A和B,两个类都是单例类,这个时候如果A有个B的实例变量,B有个A的实例变量,会发生什么情况呢?开始我以为会出现栈溢出。但是让我迷惑的是,居然没问题。只是其中一个类的 实例变量会是NULL。下面看代码。
Java代码 
public class A {  
    private static A a = new A();  
 
    private B b = B.getInstance();  
 
    private A() {  
 
    }  
 
    public static A getInstance() {  
        System.out.println("A被调用");  
        return a;  
    }  
 
    public void test() {  
        System.out.println(b);  
    }  


public class A {
private static A a = new A();

private B b = B.getInstance();

private A() {

}

public static A getInstance() {
System.out.println("A被调用");
return a;
}

public void test() {
System.out.println(b);
}
}



Java代码 
public class B {  
    private static B b = new B();  
 
    private A a = A.getInstance();  
 
    private B() {  
 
    }  
 
    public static B getInstance() {  
        System.out.println("B被调用");  
        return b;  
    }  
      
    public void test() {  
        System.out.println(a);  
    }  


public class B {
private static B b = new B();

private A a = A.getInstance();

private B() {

}

public static B getInstance() {
System.out.println("B被调用");
return b;
}

public void test() {
System.out.println(a);
}
}

Java代码 
  public class Test {  
 
/** 
* @param args 
*/ 
public static void main(String[] args) {  
                
    B b = B.getInstance();  
    b.test();  
    System.out.println("==========");             
    A a = A.getInstance();  
    a.test();  
 
                      
    //A a = A.getInstance();  
    //a.test();   
                    //System.out.println("==========");               
                   //B b = B.getInstance();  
    //b.test();  
                 //System.out.println("==========");      
 
}  

   public class Test {

/**
* @param args
*/
public static void main(String[] args) {
              
B b = B.getInstance();
b.test();
System.out.println("==========");
A a = A.getInstance();
a.test();

               
//A a = A.getInstance();
//a.test();
                 //System.out.println("==========");
                    //B b = B.getInstance();
//b.test();
                  //System.out.println("==========");

}

}


得到的结果是:
B被调用
A被调用
B被调用
A@35ce36
==========
A被调用
null


我原本在第一个getInstance的时候会出现 递归调用初始化 而
死锁的问题。但是没有,你知道JVM对于 构造方法的初始化是如何实现的。大家说说。

引用 收藏

IcyFenix 2011-04-09
大致的执行过程如下,本来想直接贴Javap的字节码了事的,不过整理了一下后发现贴了估计也看不清楚,所以过程还是用中文大致写了一些:

类Test的main()方法的B.getInstance()生成的invokestatic指令触发了类B的初始化
执行类B的<clinit>方法的过程中,显式调用了B自己的<init>方法(static b = new B())
B的<init>方法中,调用A.getInstance()生成的invokestatic指令触发了A的初始化(private A a = A.getInstance())
执行A的<clinit>方法的过程中调用了A自己的<init>方法(static a = new A())
类A的<init>方法中需要调用B.getInstance(),但是虚拟机中一个类(<class,classloader>为一个类)只会初始化一次,因此不会再触发B的初始化,既不会再执行B.<clinit>方法。
那由a.<init>触发的B.getInstance()被执行,输出第一行“B被调用”,B.getInstance()方法结束。虽然这时候B的初始化阶段尚未结束,但是解析阶段已经完成,所以getInstance()方法可以被正确执行,但这时候静态字段static B b仍然为null(注意,b.<init>方法还没完呢),所以这个B.getInstance()方法返回值为null,所以A.b为null。
A.<clinit>方法结束,第3步的invokestatic指令正式执行,即A.getInstance()被执行,输出第二行“A被调用”,返回A的实例,这时候B.a不为null了。
B.<clinit>方法结束,第1步的invokestatic指令正式执行,即B.getInstance()被执行,输出第三行“B被调用”
B.test()方法被执行,输出B.a的toString()方法结果,即第四行“A@35ce36”。
A.getInstance()方法被执行,输出第五行“A被调用”。
A.test()方法被执行,输出null,即A.b的值。


这样写应该比较好懂了吧?
引用 收藏

Anddy 2011-04-09
如果你的想法跟我一样,看看我的分析流程,就一下子明白。

B-->   B.getInstance()  --- new  B()
                    |                                      |
                    |                                      |
                    |                                      |
                new  A()  < ----    A.getInstance()

在new A() 中调用 B.getInstance(),return b ; 但是 b是静态成员,在B类加载的时候已经记录在静态存储区 【只是值为null】。 不会在去调用B.getInstance() 方法, 所以这个死锁不存在。
引用 收藏

xgj1988 2011-04-10
IcyFenix 写道
大致的执行过程如下,本来想直接贴Javap的字节码了事的,不过整理了一下后发现贴了估计也看不清楚,所以过程还是用中文大致写了一些:

类Test的main()方法的B.getInstance()生成的invokestatic指令触发了类B的初始化
执行类B的<clinit>方法的过程中,显式调用了B自己的<init>方法(static b = new B())
B的<init>方法中,调用A.getInstance()生成的invokestatic指令触发了A的初始化(private A a = A.getInstance())
执行A的<clinit>方法的过程中调用了A自己的<init>方法(static a = new A())
类A的<init>方法中需要调用B.getInstance(),但是虚拟机中一个类(<class,classloader>为一个类)只会初始化一次,因此不会再触发B的初始化,既不会再执行B.<clinit>方法。
那由a.<init>触发的B.getInstance()被执行,输出第一行“B被调用”,B.getInstance()方法结束。虽然这时候B的初始化阶段尚未结束,但是解析阶段已经完成,所以getInstance()方法可以被正确执行,但这时候静态字段static B b仍然为null(注意,b.<init>方法还没完呢),所以这个B.getInstance()方法返回值为null,所以A.b为null。
A.<clinit>方法结束,第3步的invokestatic指令正式执行,即A.getInstance()被执行,输出第二行“A被调用”,返回A的实例,这时候B.a不为null了。
B.<clinit>方法结束,第1步的invokestatic指令正式执行,即B.getInstance()被执行,输出第三行“B被调用”
B.test()方法被执行,输出B.a的toString()方法结果,即第四行“A@35ce36”。
A.getInstance()方法被执行,输出第五行“A被调用”。
A.test()方法被执行,输出null,即A.b的值。


这样写应该比较好懂了吧?



但是虚拟机中一个类(<class,classloader>为一个类)只会初始化一次。

猜你喜欢

转载自lvwenwen.iteye.com/blog/1456983