Why do this() and super() have to be the first statement in a constructor?

前端 未结 21 1974
北荒
北荒 2020-11-21 23:10

Java requires that if you call this() or super() in a constructor, it must be the first statement. Why?

For example:

public class MyClass {
    publi         


        
21条回答
  •  青春惊慌失措
    2020-11-21 23:40

    Because the JLS says so. Could the JLS be changed in a compatible manner to allow it? Yup.

    However, it would complicate the language spec, which is already more than complicated enough. It wouldn't be a highly useful thing to do and there are ways around it (call another constructor with the result of a static method or lambda expression this(fn()) - the method is called before the other constructor, and hence also the super constructor). So the power to weight ratio of doing the change is unfavourable.

    Note that this rule alone does not prevent use of fields before the super class has completed construction.

    Consider these illegal examples.

    super(this.x = 5);
    
    super(this.fn());
    
    super(fn());
    
    super(x);
    
    super(this instanceof SubClass);
    // this.getClass() would be /really/ useful sometimes.
    

    This example is legal, but "wrong".

    class MyBase {
        MyBase() {
            fn();
        }
        abstract void fn();
    }
    class MyDerived extends MyBase {
        void fn() {
           // ???
        }
    }
    

    In the above example, if MyDerived.fn required arguments from the MyDerived constructor they would need to be sleazed through with a ThreadLocal. ;(

    Incidentally, since Java 1.4, the synthetic field that contains the outer this is assigned before inner classes super constructor is called. This caused peculiar NullPointerException events in code compiled to target earlier versions.

    Note also, in the presence of unsafe publication, construction can be viewed reordered by other threads, unless precautions are made.

    Edit March 2018: In message Records: construction and validation Oracle is suggesting this restriction be removed (but unlike C#, this will be definitely unassigned (DU) before constructor chaining).

    Historically, this() or super() must be first in a constructor. This restriction was never popular, and perceived as arbitrary. There were a number of subtle reasons, including the verification of invokespecial, that contributed to this restriction. Over the years, we've addressed these at the VM level, to the point where it becomes practical to consider lifting this restriction, not just for records, but for all constructors.

提交回复
热议问题