日期:2014-05-20  浏览次数:20564 次

100分两个小问题 来抢啊
问题1:类的初始化顺序
Java code

public class Test1 {
    public static int k=0;
    public static Test1 t1=new Test1("t1");
    public static Test1 t2=new Test1("t2");
    public static int i=print("i");
    public static int n=99;
    
    public int j=print("j");
    
    {
        print("构造块");
    }
    
    static{
        print("静态块");
    }
    
    public Test1(String str){
        System.out.println((++k)+":"+str+"    i="+i+"    n="+n);
        ++i;++n;
    }
    
    public static int print(String str){
        System.out.println((++k)+":"+str+"    i="+i+"    n="+n);
        ++n;
        return ++i;
    }
    
    public static void main(String...strings ){
        
    }
}

输出结果:
1:j    i=0    n=0
2:构造块    i=1    n=1
3:t1    i=2    n=2
4:j    i=3    n=3
5:构造块    i=4    n=4
6:t2    i=5    n=5
7:i    i=6    n=6
8:静态块    i=7    n=99


问题:i和n到底是什么时候声明的,public static Test1 t1=new Test1("t1");这句会去执行构造块和构造方法,但是这时候public static int i=print("i");并没执行,i是哪里出来的?它是按顺序先声明所有变量然后才从头再挨个赋值吗?



问题2:enum的构造方法里为什么不能引用静态变量
Java code

public enum Test2 {
    A,B,C,D,E,F,G;
    public static int i=11;
    private Test2(){
        i=22;
    }
}


我从the java programming language里找了一段解释,但是看的不太明白,而且感觉解释的很浅,有点转不过来弯,麻烦高人来讲解下原因,最好能举个例子,像我上面的那段代码,我感觉没什么不可以阿。。。
There are three restrictions on the definition of an enum constructor:

All enum constructors are private. While you can use the private access modifier in the constructor declaration, by convention it is omitted. Private constructors ensure that an enum type cannot be instantiated directly.

The constructor cannot explicitly invoke a superclass constructor. The chaining to the super constructor is handled automatically by the compiler.

An enum constructor cannot use a non-constant static field of the enum.

This last restriction requires a little explanation. Because each enum constant is a static field of the enum type, the constructors are executed during static initialization of the enum class. The enum constant declarations must be the first declarations in the type, so the constructors for these values will always be the first code executed during static initialization. Any other static fields will be initialized afterward. So if a constructor were to refer to a static (non-constant) field of the enum, it would see the default uninitialized value. This would nearly always be an error, and so it is simply disallowed.


------解决方案--------------------
问题:i和n到底是什么时候声明的,public static Test1 t1=new Test1("t1");这句会去执行构造块和构造方法,但是这时候public static int i=print("i");并没执行,i是哪里出来的?它是按顺序先声明所有变量然后才从头再挨个赋值吗?
关于这个问题:类的生命周期分为如下几个阶段,Loading,Linking,Initialization.
Loading之后会对class文件进行Verification,也就是验证.然后是Preparation阶段,注意在这个阶段所有的类变量,也就是class变量,会被默认初始化,也就是int,long,short,浮点等基本类型初始化为0,引用初始化为null,boolean被初始化为false.也就是到这个阶段各个static变量已经有默认的值了,后面会进入Resolution阶段,然后才是初始化,即Initialization,这个阶段会执行static初始化,把变量初始化为你指定的值.也就是在这个阶段k=0;Test1 t1=new Test1("t1");才开始执行的,这时候i=print("i");还没有执行到,i仍然取在 Preparation阶段得到的默认值0.
这样应该清楚了吧.
------解决方案--------------------
其实你的第一个例子很好,enum也是类似,就是在静态初始化的时候调用了构造方法,如果你在这个方法里使用了非final的静态变量,这时候的值还不是你初始化后的值,java为了避免这种不确定性,干脆禁止你这么干了.