在构造函数中初始化静态变量

时间:2012-07-06 08:37:18

标签: java singleton

请查看以下代码:

public class Foo {
    private static Foo sigleton=new Foo();
    private static int count1;
    private static int count2=0;

    private Foo (){
        count1++;
        count2++;
    }

    public static Foo getInstance(){
        return sigleton;
    }

    public static void main(String[] args) {
        //Foo f= Foo.getInstance(); // case 1
        //Foo f= new Foo(); // case 2
        System.out.println(f.count1);
        System.out.println(f.count2);
    } 
}

对于每次运行,取消注释main方法中的一行。

为什么案例1和2的输出不同?

4 个答案:

答案 0 :(得分:6)

仅仅因为在第一种情况下,构造了一个Foo对象,但在第二种情况下,构造了两个Foo个对象。

您静态初始化sigleton字段 - 因此在加载类时,始终会调用Foo构造函数(正如您为字段初始化程序指定的那样)。

现在在案例1中,您只是调用方法,它返回已经构造的sigleton对象 - 因此不再调用其他构造函数。在案例2中,您显式构造了一个新的Foo对象 - 但仍将构造sigleton。因此,在后一种情况下,会创建两个对象,构造函数总共运行两次,因此count1count2将更大一个。

答案 1 :(得分:3)

比你的问题更有趣的是count1 == count2 + 1

原因是静态声明按编译器找到它们的顺序运行,因此第一次调用Foo会调用以下语句:

private static Foo sigleton = null; //default value for objects
private static int count1 = 0; //default value for int
private static int count2 = 0; //default value for int

sigleton = new Foo(); //first static initializer => count1 = 1 AND count2 = 1
count2 = 0; //second static initializer

从那时起,count1和count2一起递增,你将始终拥有count1 == count2 + 1

底线:不要写那种代码!

答案 2 :(得分:2)

Java将首先将静态变量初始化为默认值(null,0和等效值)。无论是否指定初始值,都会执行此操作。

然后,它将从类的开头到底部运行代码的所有静态(非静态方法!)。初始化也被视为代码块,它按文件中指定的顺序运行。因此,这样的代码:

// static block of code in front

static Type variable = initialValue;

// static block of code in-between

static OtherType anotherVariable = someInitialValue;

// static block of code below

大致相当于(粗略 - 因为它们在语法上不等同)

static Type variable;
static OtherType anotherVariable;

// static block of code in front

static {
    variable = initialValue;
}

// static block of code in-between

static {
    anotherVariable = someInitialValue;
}

// static block of code below

(在对构造函数的任何调用之前,所有非静态的代码都将在构造函数被调用之前运行。但它与OP的代码片段并不相关。)

从上面的方案中,将调用Foo()构造函数。 count1count2将初始化为1。

执行singleton = new Foo()初始化程序后,它将继续执行初始化count2 = 0,并有效地将count2设置为0。

此时,我们将输入main()功能,然后打印出来。如果第二次调用构造函数,如上所述,将在构造函数之前运行非静态代码块,并且将再次调用构造函数以增加count1count2的值。这一步没有什么奇怪的事情发生。

您可以尝试编译并运行这段代码来查看效果:

class Foo {
    static {
      System.out.println("static 0: " + Foo.sigleton + " " + Foo.sigleton.count1 + " " + Foo.sigleton.count2);
    }

    private static Foo sigleton=new Foo();

    static {
      System.out.println("static 1: " + sigleton + " " + sigleton.count1 + " " + sigleton.count2);
    }

    private static int count1;

    static {
      System.out.println("static 2: " + sigleton + " " + sigleton.count1 + " " + sigleton.count2);
    }

    private static int count2=0;

    static {
      System.out.println("static 3: " + sigleton + " " + count1 + " " + count2);
    }

    {
      System.out.println("non-static 1: " + sigleton + " " + count1 + " " + count2);
    }

    private Foo (){
        count1++;
        count2++;

        System.out.println(count1 + " " + count2);
    }

    {
      System.out.println("non-static 2: " + sigleton + " " + count1 + " " + count2);
    }

    public static Foo getInstance(){
        return sigleton;
    }

    public static void main(String[] args) {
        Foo f= Foo.getInstance(); // case 1
        System.out.println(f.count1);
        System.out.println(f.count2);
        Foo t= new Foo(); // case 2
        System.out.println(t.count1);
        System.out.println(t.count2);
    } 
}

答案 3 :(得分:1)

在情况2中,构造函数Foo()被调用2次,一次是在初始化private static Foo时,第二次是从main方法调用。如果使用getInstance()方法获取Foo,则不会发生第二次调用。