public class A{
static String a = "aaa";
static String b = new B().sayHi_B();

static{
System.out.println("A.static:A's vars are:{" + A.a + ',' + A.b+ "}");//2
}

void sayHi_A(){
System.out.println("A.sayHi():A's vars are:{" + A.a + ',' + A.b+ "}");//3
}

public static void main(String[] args){
}
}class B{
static{
System.out.println("B.static #1:A's vars are:{" + A.a + ',' + A.b+ "}");//1
new A().sayHi_A();
System.out.println("B.static #2:A's vars are:{" + A.a + ',' + A.b+ "}");//4
}

String sayHi_B(){
return "HI";
}
}
//我的答案
//B.static #1:A's vars are:{aaa,null}
//A.static:A's vars are:{aaa,null}
//A.sayHi():A's vars are:{aaa,null}
//B.static #2:A's vars are:{aaa,HI}//实际答案
//B.static #1:A's vars are:{aaa,null}
//A.sayHi():A's vars are:{aaa,null}
//B.static #2:A's vars are:{aaa,null}
//A.static:A's vars are:{aaa,HI}

解决方案 »

  1.   

    顺序执行,static从最内层执行。
      

  2.   

    顺序执行,static从最内层执行。
      

  3.   

    顺序执行,static从最内层执行。
      

  4.   

    能说的详细点吗,我主要是不明白new A()的时候不应该先执行静态代码块输出A.static:A's vars are:{aaa,HI}这句吗,可是为什么最后输出的这个,而先输出的是A.sayHi():A's vars are:{aaa,null}
      

  5.   

    从LZ的答案来看应该已经大致上明白了吧。JVM加载类的顺序是从主类开始,之后用到哪个类再加载哪个(没用到的类不会加载)。类加载的步骤包括基本信息的加载及初始化。
    基本信息的加载指声明类变量及方法、实例属性及方法等基本信息,并将类变量置默认值。初始化指类变量的初始化及静态块的运行,它们按从上到下的顺序执行。本例中,先加载主类A:
    1.声明类变量a、b,实例方法sayHi_A,并将a、b置默认值null。
    2.初始化类变量a="aaa"。
    3.由于类变量b的初始化用到了类B,所以这里暂停A的加载,转入B的加载。
    4.声明实例方法sayHi_B。
    5.执行静态块,由于A.a已初始化为aaa,而A.b由于类B的加载而未初始化,仍然为null。输出B.static #1:A's vars are:{aaa,null}。
    6.由于类A的基本信息已加载完成,所以可以调用其实例方法sayHi_A(注:类能够实例化的前提是基本信息加载完成而不是初始化完成,否则像本例的情况会因为A与B争先初始化而发生死锁),输出A.sayHi():A's vars are:{aaa,null}。
    7.静态块的第三行,输出B.static #2:A's vars are:{aaa,null}。
    8.完成类B的初始化,继续A的初始化。调用B的实例方法初始化A.b="HI"。
    9.运行静态块,输出A.static:A's vars are:{aaa,HI}。
    10.类A初始化完成。说实说,这个题目真的很奇葩(虽然利用非静态块和构造函数同样可以设计出很奇葩的题目……)。
      

  6.   

    A初始化过程有点漫长,静态部分,非静态部分都是类初始化的一部分,是分开执行的。但是无论那个类执行一旦开始,而类生命的还是是在new的时候,只不过,此时这个类未必装配完成。