What is object field initialization and constructor order in Java

Today I finished the following code in the code (which, I admit, is strange, and since then I will reorganize it). When I ran my unit test, I found that the initialization of the field was not set by the time the superclass constructor started. I realized that I do not quite understand the initialization order of the constructor / field, so I publish in the hope that someone will explain to me the order in which they occur.

class Foo extends FooBase { String foo = "foobar"; @Override public void setup() { if (foo == null) { throw new RuntimeException("foo is null"); } super.setup(); } } class FooBase { public FooBase() { setup(); } public void setup() { } } @Test public void testFoo() { new Foo(); } 

The abbreviated feedback from JUnit is as follows, I assume I was expecting $ Foo. <init> to install foo.

 $Foo.setup $FooBase.<init> $Foo.<init> .testFoo 
+6
source share
3 answers

Yes, in Java (unlike C #, for example), field initializers are called after the superclass constructor. This means that any calls to the overridden method from the constructor will be called before the field initializers are executed.

Order:

  • Initialize a superclass (call these steps recursively)
  • Run field initializers
  • Execute the constructor body (after the chain of constructors that was already completed in step 1)

Basically, it is a bad idea to call non-confidential methods in constructors. If you do, write it very clearly so that anyone redefining the method knows that the method will be called before the field initializer (or constructor body).

See JLS Section 12.5 for details.

+7
source

The first constructor operation is always a call to the superclass constructor. Not having a constructor explicitly defined in the class is equivalent to having

 public Foo() { super(); } 

The constructor of the base class is thus called before any subclass field is initialized. And your base class is doing something to avoid: calling an override method.

Since this method is overridden in a subclass, it is called on an object that is not yet fully constructed, and thus sees the subclass field as null.

+3
source

Here is an example of polymorphism in pseudo-C # / Java:

 class Animal { abstract string MakeNoise (); } class Cat : Animal { string MakeNoise () { return "Meow"; } } class Dog : Animal { string MakeNoise () { return "Bark"; } } Main () { Animal animal = Zoo.GetAnimal (); Console.WriteLine (animal.MakeNoise ()); } 

The main function does not know the type of animal and depends on the specific behavior of the implementation of the MakeNoise () method.

 class A { A(int number) { System.out.println("A's" + " "+ number); } } class B { A aObject = new A(1); B(int number) { System.out.println("B's" + " "+ number); } A aObject2 = new A(2); } public class myFirstProject { public static void main(String[] args) { B bObj = new B(5); } } 

from: A 1 A 2 B 5

My rules: 1. Do not initialize the default values ​​in the declaration (null, false, 0, 0.0 ...). 2. Assume initialization in the declaration if you do not have a constructor parameter that changes the value of the field. 3. If the field value changes due to the constructor parameter, place the initialization in the constructors. 4. Be consistent in your practice. (most important rule)

 public class Dice { private int topFace = 1; private Random myRand = new Random(); public void Roll() { // ...... } } 

or

 public class Dice { private int topFace; private Random myRand; public Dice() { topFace = 1; myRand = new Random(); } public void Roll() { // ..... } } 
0
source

All Articles