Attributes initialization Java

I was collecting design paterns for a personal cheat sheet and I found a, at least for me, strange piece of code at Head First Design Patterns (By Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra).

I don't think I am allowed to post here the piece of code exactly at is written in the book but I will reproduce the code that shocked me:

Assuming we have previously deffined the class A with a public method runSomeCode(), then we have class B as follows:

public class B {

    A a;
    A b;
    A x = a;

    public B() {
        a = new A();
        b = new A();
    }

    public void testB()
    {
        x.runSomeCode();
    }    
}

My first impression looking at this code is that any call to a B instance testB method should throw a NullPointerException but I couldn't imagine they would had published such a mistake.

If the book is right then I understand that

x = a;

must be done at the end of B constructor execution but I am still surprised by this sintaxis and my questions are:

EDIT THis is the book example:

enter image description here

The case I am concerned about is when numberGumballs = 0;

EDIT II

I think I know what happened with the example.

In the book, the referenced classes are NOT declared static but few minutes ago I thought it could compile if A was static. So, maybe, the book authors got the code from a larger project where static classes were being used. So I tried this and, this time, it does work but the example seems to continue being wrong and the following code doesn't make any sense concerning State pattern.

public class B {

    public static class Base {
        public static void runSomeCode() { System.out.println("Base!"); }
    }

    public static class A extends Base {
        public static void runSomeCode() { System.out.println("A!"); }
   }; 

    A a;
    A b;
    A x = a;

    public B() {
        a = new A();
        b = new A();
    }

    public void testB()
    {
        x.runSomeCode();
    }    
}

Yet Another Edit

It seems I have not been the first one to notice this problem in the book example, at O'Reilly site errata section, under unconfirmed erratas sub-section you can find:

enter image description here

Upvotes: 3

Views: 1343

Answers (3)

Adarsh
Adarsh

Reputation: 3641

When you first create an object of type B, the fields that have any initializations are initialized first. So, A x = a; is executed first, even before the code in the constructor is executed which sets the value of x to null, since a has not been instantiated and is just a null reference of type A. After this, the following code is executed which creates the two objects.

public B() {
    a = new A();
    b = new A();
}

x is still null at this point. So when you try to execute a method in A class using x, it will throw a null pointer exception.

Upvotes: 1

BadIdeaException
BadIdeaException

Reputation: 2124

To answer your questions:

  1. I believe you are wrong, according to the Java 8 Specification field initializers are executed before the constructor body.
  2. I believe it has, but don't feel like going through the specification for every version. I'm not aware of any changes though.
  3. I doubt it, seeing how it's part of the specification and would break compatibility if they changed it. But
  4. In this case the code can easily be changed over to explicitly stating the order of initialization by moving the assignment to x into the constructor. Having it as a field initializer has no benefits that would be obvious to me.

What's supposed to be the point of this "pattern"? You just end up with two references where one would have done...why not just use a instead?

Upvotes: 1

Marboni
Marboni

Reputation: 2459

Am I wrong?

In-place variable initialization works before initialization in constructor, in the same order as variable defined in code.

Has Java always behaved like this?

Yes.

In that case (I personally consider this a little bit confusing): Is it likely to be removed in future Java versions?

No, Java is backward compatible language, this is basic and will not be changed.

Would you try to avoid it?

If you want in-place initialization, make sure that it's independent of initializing of other variables. Otherwise initialize it in the constructor. Don't make complex in-place initialization.

Upvotes: 1

Related Questions