Can a java subclass's private final field be initialized before the super constructor completes?

前端 未结 3 1771
感动是毒
感动是毒 2021-01-23 03:58

I have a pair of classes looking like this;

public abstract class Class1 {

//...

    public Class1() {
        //...
        function2();
        //...
    }

         


        
相关标签:
3条回答
  • 2021-01-23 04:54

    Your design is an instance of the "leaked this problem" and is an anti-pattern in Java. You should never call out to a publicly overridable method from a constructor.

    0 讨论(0)
  • 2021-01-23 04:56

    super classes are always initialised before subclasses. Only static fields of a sub class can be initialised first.

    You can call an overridden method from the super class which then accesses a field which is not initialised. This is considered bad practice.

    0 讨论(0)
  • 2021-01-23 04:59

    Short answer - no. A superclass' constructor, field initialisers and instance initialisers are always called before the subclass'.

    The order of calls is formally defined in section 8.8.7.1 of the JLS. Summarising the relevant last parts (where S is the superclass and C is the subclass):

    After determining the immediately enclosing instance of i with respect to S (if any), evaluation of the superclass constructor invocation statement proceeds by evaluating the arguments to the constructor, left-to-right, as in an ordinary method invocation; and then invoking the constructor.

    Finally, if the superclass constructor invocation statement completes normally, then all instance variable initializers of C and all instance initializers of C are executed. If an instance initializer or instance variable initializer I textually precedes another instance initializer or instance variable initializer J, then I is executed before J.

    So when the superclass constructor runs, the subclass and all its fields are completely uninitialised. It's bad practice to call overridden methods from a constructor for this reason. You're essentially letting a reference to the object "escape" from its constructor, which means all the guarantees of construction are off (including things like final fields changing value, etc.).

    Calling an abstract method from a constructor is almost always the wrong thing to do. Depending on the implementation of the method in the subclass(es) you might get away with it in some case (i.e. if the method does not depend on any state at all), but it will almost certainly cause a hard-to-debug failure at some point.

    For example, would you expect there to be a difference between:

    protected String function2() {
        return "foo";
    }
    

    and

    private final String foo = "foo";
    
    protected String function2() {
        return foo;
    }
    

    Analysing problems like this is hard, because they break the mental model of how classes work. Best to avoid this situation altogether.

    0 讨论(0)
提交回复
热议问题