TIJ上的一个例子:class Bowl {
Bowl(int er) {
System.out.println("Bowl(" + er + ")");
}
void f1(int er) {
System.out.println("f1(" + er + ")");
}
}class Table {
static Bowl bowl1 = new Bowl(1);
Table() {
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int er) {
System.out.println("f2(" + er + ")");
}
static Bowl bowl2 = new Bowl(2);
}class Cupboard {
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard(){
System.out.println("Cupboard()");
bowl4.f1(1);
}
void f3(int er) {
System.out.println("f3(" + er + ")");
}
static Bowl bowl5 = new Bowl(5);
}
public class StaticInitialization { /**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub

System.out.println("Creating new Cupboard() in main");
new Cupboard();
System.out.println("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1); }
static Table table = new Table();
static Cupboard cupboard = new Cupboard();}        运行结果如下:
        Bowl(1)
        Bowl(2)
        Table()
        f1(1)
        Bowl(4)
        Bowl(5)  
        Bowl(3)
        Cupboard()
        f1(1)
        Creating new Cupboard() in main
        Bowl(3)
        Cupboard()
        f1(1)
        Creating new Cupboard() in main
        Bowl(3)
        Cupboard()
        f1(1)
        f2(1)
        f3(1)
        同时,书上对这个例子进行了总结:
        “总结一下对象的创建过程,假设有个名为Dog的类:
          1.即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
          2.然后载入Dog.class(这将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
          3.当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
          4.这块存储空间将被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值,而引用则被设置成了null。
          5.执行所有出现在字段定义处的初始化动作。
          6.执行构造器。”
        书上又说,“要执行main()(静态方法),必须加载StaticInitialization类,然后静态域table和cupboard被初始化,这将导致它们对应的类也被加载,并且由于它们也都包含静态的Bowl对象,因此Bowl随后也被加载。这样,在这个特殊的程序中的所有类在main()开始之前就都被加载了。”
        不过我仍有疑问,加载StaticInitialization类后有关静态初始化的所有动作都会执行,那么有关静态初始化指的是什么?main()这个静态方法是否属于要静态初始化的一部分?网上有人(原文链接http://student.csdn.net/space.php?uid=120826&do=blog&id=13762)说“但主类比较特殊,主方法会在构造器之前,static变量初始化之后调用,这是由于Java的惰性初始化,在main方法被调用之前无法知道是否存在主类的实例。”不知大家怎么看。
        另外,如果将static Table table = new Table();static Cupboard cupboard = new Cupboard();这两句放在main中,会出错“Illegal modifier for parameter table; only final is permitted”,这又是为什么?是static不能应用于局部变量只能作用于域的原因还是main的某些原因呢?
        最后域的概念究竟如何理解?只是一个决定其中变量名的可见性和生命周期的概念吗?static的域又是一个怎样的概念?
        问题挺多还挺杂,大家费心了。

解决方案 »

  1.   

    我的理解是静态初始化是指static变量和static块,在该类的第一次调用时进行,即一加载.class文件就会进行静态初始化。
    那么什么时候加载.class文件呢,我理解是第一次调用该类的静态方法或静态变量时加载。main方法和其他静态方法我认为是相同的。
    例子如下,输出结果和楼主的例子一样
    class Bowl {
        Bowl(int er) {
            System.out.println("Bowl(" + er + ")");
        }
        void f1(int er) {
            System.out.println("f1(" + er + ")");
        }
    }class Table {
        static Bowl bowl1 = new Bowl(1);
        Table() {
            System.out.println("Table()");
            bowl2.f1(1);
        }
        void f2(int er) {
            System.out.println("f2(" + er + ")");
        }
        static Bowl bowl2 = new Bowl(2);
    }class Cupboard {
        Bowl bowl3 = new Bowl(3);
        static Bowl bowl4 = new Bowl(4);
        Cupboard(){
            System.out.println("Cupboard()");
            bowl4.f1(1);
        }
        void f3(int er) {
            System.out.println("f3(" + er + ")");
        }
        static Bowl bowl5 = new Bowl(5);
    }
    class StaticInitialization {    /**
         * @param args
         */
        public static void a() {
            // TODO Auto-generated method stub
            
            System.out.println("Creating new Cupboard() in main");
            new Cupboard();
            System.out.println("Creating new Cupboard() in main");
            new Cupboard();
            table.f2(1);
            cupboard.f3(1);    }
        static Table table = new Table();
        static Cupboard cupboard = new Cupboard();}public class Test
    {
    public static void main(String[] args)
    {
    StaticInitialization.a();
    }
    }
      

  2.   

    多谢指点。感觉“但主类比较特殊,主方法会在构造器之前,static变量初始化之后调用,这是由于Java的惰性初始化,在main方法被调用之前无法知道是否存在主类的实例。”这句话解释得还是挺合理的。
      

  3.   

    我觉得这里TIJ的解释不错,构造方法实际上也是静态方法,程序运行时会最先调用主类的主方法,主类的构造方法还不会调用,第一次调用静态方法时.class文件会先被加载,static变量初始化。所以主类的主方法“会在构造器之前,static变量初始化之后调用”
      

  4.   


    关于这点, 是因为在java的变量中, 只有域变量才能被定义为static的, 静态域也叫类域, 从这个方面来看, 局部变量是不能定义为static的. 静态域是属于类的, 而不属于某个对象, 它是一个公共的资源.
    另外, 对于域, 我个人觉得, 域就是指的类的属性, 里面的所有的变量, 因为所谓的域初始化, 都是指的是实例化这个类时对变量的初始化. 以上都只是个人理解, 有什么不对的地方, 请指出, 谢谢.
      

  5.   

    “域”就是“Field”,这是一个极其蹩脚的译法,应该译作“字段”。“字段”是Java对成员变量的特殊称谓,“静态域”其实就是静态成员变量。
      

  6.   

    这种题看着就头晕!
    是啊,我也感觉 field 应译为“字段”,或者意译为“成员变量”。“域”的话感觉挺不知所云的,呵呵。
      

  7.   

    其实我们不用把问题想得太复杂,static只能用来修饰类的实例变量,static表示该类的所有实例都可以共享该变量,静态变量/块会在该类的任何对象创建之前/任何静态方法执行之前就完成初始化
      

  8.   

    就是说static修饰的实例引用,只要是同一个类的,指向的其实都是堆上同一个区域。而既然该类的所有实例都可以共享,所以在被使用之前,这个堆上的东西必须有个初值,好让别人用。可以这么理解吗?
      

  9.   

    汗!!!! 域就是成员变量!叫法不同而已!比如
    class Foo {
      int bar;
    }bar就是Foo类的一个域,即一个成员变量!域、字段、成员变量,指的都是一个东西,不同叫法而已。但是“域”有时还指“作用域”(Scope),那就完全是另一种东西了。建议楼主看英文原著!
      

  10.   

    非常正确,另外如果变量既是static又是final的话,就必须在声明的时候赋值或者放在static块中集体赋值