What is object field initialization and constructor order in Java

前端 未结 3 2014
半阙折子戏
半阙折子戏 2020-12-06 18:33

I ended up the following scenario in code earlier today (which I admit is kinda weird and I have since refactored). When I ran my unit test I found that a field initializat

相关标签:
3条回答
  • 2020-12-06 19:16

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

    The ordering is:

    • Initialize superclass (recursively invoke these steps)
    • Execute field initializers
    • Execute constructor body (after any constructor chaining, which has already taken place in step 1)

    Basically, it's a bad idea to call non-final methods in constructors. If you're going to do so, document it very clearly so that anyone overriding the method knows that the method will be called before the field initializers (or constructor body) are executed.

    See JLS section 12.5 for more details.

    0 讨论(0)
  • 2020-12-06 19:19

    A constructor's first operation is always the invocation of the superclass constructor. Having no constructor explicitely defined in a class is equivalent to having

    public Foo() {
        super();
    }
    

    The constructor of the base class is thus called before any field of the subclass has been initialized. And your base class does something which should be avoided: call an overridable method.

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

    0 讨论(0)
  • 2020-12-06 19:28

    Here's 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 doesn't know the type of the animal and depends on a particular implementation's behavior 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);
       }
    }
    

    out: A's 1 A's 2 B's 5

    My rules: 1. Don't initialize with the default values in declaration (null, false, 0, 0.0...). 2. Prefer initialization in declaration if you don't have a constructor parameter that changes the value of the field. 3. If the value of the field changes because of a constructor parameter put the initialization in the constructors. 4. Be consistent in your practice. (the 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 讨论(0)
提交回复
热议问题