0

Look at the following code:

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);
    } 
}

For each run, uncomment one of the lines in the main method.

Why is the output in case 1 and 2 different?

7
  • 3
    it isn't a valid code! f cannot be declared twice Commented Jul 6, 2012 at 8:39
  • 1
    you initialize f, and call t.count1?? Commented Jul 6, 2012 at 8:40
  • 2
    A more interesting question would be why count1 and count2 are different. Commented Jul 6, 2012 at 8:42
  • 1
    The correct name for sigleton is singleton. Commented Jul 6, 2012 at 8:43
  • 3
    Setting a static field in a constructor is a bad idea. This often leads to confusion and programming errors IMHO. If you have a singleton, make it clear rather than using a hybrid static/non-static object. Commented Jul 6, 2012 at 8:44

4 Answers 4

6

Simply because in the first case, one Foo object is constructed, but in the second case, two Foo objects are constructed.

You initialise the sigleton field statically - so when the class is loaded, the Foo constructor is always called (as you specified for the field initialiser).

Now in case 1, you're just calling a method, which returns the sigleton object which has already been constructed - so no further constructors are called. In case 2, you explicitly construct a new Foo object - but the sigleton will still be constructed. Hence in this latter case, two objects are created, the constructor is run twice in total, and so count1 and count2 will be one greater.

Sign up to request clarification or add additional context in comments.

Comments

4

Even more interesting than your question is the fact that count1 == count2 + 1.

The reason is that static declarations are run in the order in which they are found by the compiler, so the first call to Foo calls the following statements:

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

From that point on, count1 and count2 are incremented together and you will always have count1 == count2 + 1.

Bottom line: don't write that kind of code!

1 Comment

This snippet of code reveals the order of execution of static and non-static code blocks in Java ideone.com/OFHF8
2

Java will first initialize the static variables to default values (null, 0, and equivalent). This is done regardless of whether a initial value is specified or not.

It will then run all static blocks of code (not static method!), from the beginning to the bottom of the class. Initialization is also considered block of code, and it is run in the order as specified in file. Therefore, such code:

// 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

Is roughly equivalent to (roughly - since they are not syntactically equivalent)

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

(Just before any call to the constructor, all non-static blocks of code will be run before the constructor is called. It is not very relevant to the OP's piece of code, though.)

From the scheme above, Foo() constructor will be called. And count1 and count2 will be initialized to 1.

After executing the singleton = new Foo() initializer, it will go on to execute the initialization count2 = 0, and effectively set count2 to 0.

At this point, we will enter the main() function, and print out. If the constructor is called the second time, as mentioned above, non-static blocks of code will be run before the constructor, and the constructor will be called again to increment value of count1 and count2 each by 1. Nothing strange happens at this step.

You can try compile and run this piece of code to see the effect:

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);
    } 
}

Comments

1

In case 2 the constructor Foo() is called 2 times, once when initialising the private static Foo and a second time from the main method. This second call does not occur if using the getInstance() method to obtain a Foo.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.