class Insect{
          private int i = 9;
          protected int j;
          Insect( ){
                    System.out.println("i = " + i + ",j = " + j);
                    j = 39;
          }
          private static int x1 = printInit("static Insect.x1 initialized");
          static int printInit(String s) {
                    System.out.println(s);
                    return 47;
          }
}public class Beetle extends Insect{
          private int k = printInit("Beetle.k initialized");
          public Beetle(){
                    System.out.println("k = " + k);
                    System.out.println("j = " + j);
          }
          private static int x2 = printInit("static Beetle.x2 initialized");
          public static void main(String[] args)  {
                    System.out.println("Beetle constructor");
                    Beetle b = new Beetle();                   
          }
}
中,main函数的Beetle constructor在Insect和Bettle类中的静态变量被初始化后才打印
运行结果:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9,j = 0
Beetle.k initialized
k = 47
j = 39
而class Insect{
          private int i = 9;
          protected int j;
          Insect( ){
                    System.out.println("i = " + i + ",j = " + j);
                    j = 39;
          }
          private static int x1 = printInit("static Insect.x1 initialized");
          static int printInit(String s) {
                    System.out.println(s);
                    return 47;
          }
}class Beetle extends Insect{
          private int k = printInit("Beetle.k initialized");
          public Beetle(){
                    System.out.println("k = " + k);
                    System.out.println("j = " + j);
          }
          private static int x2 = printInit("static Beetle.x2 initialized");
          
}public class TestBeele {
          public static void main(String[] args)  {
                    System.out.println("Beetle constructor");
                    Beetle b = new Beetle();
          }
}中main函数的打印语句会在Beetle和Insect中的静态变量被初始化前打印,
运行结果:
Beetle constructor
static Insect.x1 initialized
static Beetle.x2 initialized
i = 9,j = 0
Beetle.k initialized
k = 47
j = 39
为什么呢?望高手解答

解决方案 »

  1.   

    是个问题~~thinking in java那本书好像第五章有讲~~构造器那张...我忘了`囧...
      

  2.   

    静态对象在实例化前先执行,在第三个类里的那个例子是输出后再引用上面的类,引用才会调用classloader装载类,装载并不代表实例化。静态成员在装载时就会被执行了。
    不过呢如果是多线程下如果你的static比较耗时而请求又比较密集的话,你那样初始化会给你个未定义的错误呵呵。
      

  3.   


    class Insect{
              private int i = 9;
              protected int j;
              Insect( ){
                        System.out.println("i = " + i + ",j = " + j);
                        j = 39;
              }
              private static int x1 = printInit("static Insect.x1 initialized");
              static int printInit(String s) {
                        System.out.println(s);
                        return 47;
              }
    }public class Beetle extends Insect{
              private int k = printInit("Beetle.k initialized");
              public Beetle(){
                        System.out.println("k = " + k);
                        System.out.println("j = " + j);
              }
              private static int x2 = printInit("static Beetle.x2 initialized");
              public static void main(String[] args)  {
                        System.out.println("Beetle constructor");
                        Beetle b = new Beetle();                   
              }
    }
    用上面的代码做例子讲讲JVM的运行过程:     (1) 首先是运行包换了main()方法的主类Beetle,此时JVM会将Beetle.class进行加载,并在内存的方法区中开辟空间用来存放类静态成员数据,并设置默认值(比如int默认值为0)。然后调用初始化方法clinit()来对这些类静态成员数据进行初始化计算,比如上面的:private static int x2 = printInit("static Beetle.x2 initialized")。因此,第一次加载Beetle类并初始化就会运行上面的x2=....语句。
                  第一个打印的是:static Beetle.x2 initialized
         (2)再加载Beetle类之后,JVM会再把Beetle的父类Insect加载进来,并同时开辟内存并初始化类静态成员变量,过程同上。因此,会执行private static int x1 = printInit("static Insect.x1 initialized");语句
                  第二个打印的是:static Insect.x1 initialized
        (3)然后JVM会为main()方法创建一个栈帧并加入到栈中,并开始执行此方法中的指令。那么第一条指令就是一条打印语句,因此: System.out.println("Beetle constructor");
                  第三个打印的是:Beetle constructor
            接着执行 Beetle b = new Beetle(); 将在堆中创建一个Beetle对象,实际上JVM会调用构造器和实例变量的初始化语句进行初始化。然而在执行Beetle对象的初始化之前,会首先调用其父类的构造器和实例变量的初始化语句。因此JVM会首先执行下面这几条语句。这里要注意,对于实例变量j而言,在没有初始化之前其值为默认值0.     
              private int i = 9;
              protected int j;
              Insect( ){
                        System.out.println("i = " + i + ",j = " + j);
                        j = 39;
              }
                  第四条打印语句将是:i = 9,j = 0
           当继承父类的实例变量初始化完毕之后,JVM会对Beetle类的实例变量开辟空间并进行初始化,此时调用下面的语句:
             private int k = printInit("Beetle.k initialized");
              public Beetle(){
                        System.out.println("k = " + k);
                        System.out.println("j = " + j);
              }
           因此后面将打印出:
    Beetle.k initialized
    k = 47
    j = 39
      

  4.   

    楼上回答的挺好的。
    主要区别的在jvm加载Beetle类的时机不同。
    第一个因为他本身一个应用类,要运行main就必须先加载它。所有static的那些在main方面还没有执行的时候就执行了
    第二个同理,在是在要new的时候才需要加载它。
      

  5.   

    4楼的,你的分析有问题,
    打印顺序应是先static Insect.x1 initialized,
    再static Insect.x2 initialized,应该先初始化基类的静态变量
      

  6.   

    把4L的错误部分修改一下:  (1) 首先是运行包换了main()方法的主类Beetle,此时JVM会将Beetle.class进行加载,并在内存的方法区中开辟空间用来存放类静态成员数据,并设置默认值(比如int默认值为0)。然后对常量池进行解析,也就是在Beetle类型的常量池中寻找类,接口,字段和方法的符号引用,并将其转化为内存的直接引用。在这个过程中,会发现Beetlt有父类Insect,这个时候会通过类转载器加载父类类型Insect。然后对父类中的静态成员变量开辟空间并进行初始化,也就是运行  private static int x1 = printInit("static Insect.x1 initialized"); 
             第一次打印: static Insect.x1 initialized
      
      (2)对父类初始化完毕之后,然后再进行Beetlt初始化类静态成员变量,过程同上。因此,会执行  private static int x2 = printInit("static Beetle.x2 initialized");  第二个打印的是:static Beetle.x2 initialized
      

  7.   

    重点还是在main方法上面当Beetle 类调用main方法时都会初始化该方法所在类的静态成员