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

前端 未结 21 1906
北荒
北荒 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:20
    class C
    {
        int y,z;
    
        C()
        {
            y=10;
        }
    
        C(int x)
        {
            C();
            z=x+y;
            System.out.println(z);
        }
    }
    
    class A
    {
        public static void main(String a[])
        {
            new C(10);
        }
    }
    

    See the example if we are calling the constructor C(int x) then value of z is depend on y if we do not call C() in the first line then it will be the problem for z. z would not be able to get correct value.

    0 讨论(0)
  • 2020-11-21 23:21

    I've found a way around this by chaining constructors and static methods. What I wanted to do looked something like this:

    public class Foo extends Baz {
      private final Bar myBar;
    
      public Foo(String arg1, String arg2) {
        // ...
        // ... Some other stuff needed to construct a 'Bar'...
        // ...
        final Bar b = new Bar(arg1, arg2);
        super(b.baz()):
        myBar = b;
      }
    }
    

    So basically construct an object based on constructor parameters, store the object in a member, and also pass the result of a method on that object into super's constructor. Making the member final was also reasonably important as the nature of the class is that it's immutable. Note that as it happens, constructing Bar actually takes a few intermediate objects, so it's not reducible to a one-liner in my actual use case.

    I ended up making it work something like this:

    public class Foo extends Baz {
      private final Bar myBar;
    
      private static Bar makeBar(String arg1,  String arg2) {
        // My more complicated setup routine to actually make 'Bar' goes here...
        return new Bar(arg1, arg2);
      }
    
      public Foo(String arg1, String arg2) {
        this(makeBar(arg1, arg2));
      }
    
      private Foo(Bar bar) {
        super(bar.baz());
        myBar = bar;
      }
    }
    

    Legal code, and it accomplishes the task of executing multiple statements before calling the super constructor.

    0 讨论(0)
  • 2020-11-21 23:22

    Simply because this is the inheritance philosophy. And according to the Java language specification, this is how the constructor's body is defined:

    ConstructorBody: { ExplicitConstructorInvocationopt    BlockStatementsopt }

    The first statement of a constructor body may be either

    • an explicit invocation of another constructor of the same class (by using the keyword "this"); or
    • an explicit invocation of the direct superclass (by using the keyword "super")

    If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments. And so on.. there will be a whole chain of constructors called all the way back to the constructor of Object; "All Classes in the Java platform are Descendants of Object". This thing is called "Constructor Chaining".

    Now why is this?
    And the reason why Java defined the ConstructorBody in this way, is that they needed to maintain the hierarchy of the object. Remember the definition of the inheritance; It's extending a class. With that being said, you cannot extend something that doesn't exist. The base (the superclass) needs to be created first, then you can derive it (the subclass). That's why they called them Parent and Child classes; you can't have a child without a parent.

    On a technical level, a subclass inherits all the members (fields, methods, nested classes) from its parent. And since Constructors are NOT members (They don't belong to objects. They are responsible of creating objects) so they are NOT inherited by subclasses, but they can be invoked. And since at the time of object creation only ONE constructor is executed. So how do we guarantee the creation of the superclass when you create the subclass object? Thus the concept of "constructor chaining"; so we have the ability to invoke other constructors (i.e. super) from within the current constructor. And Java required this invocation to be the FIRST line in the subclass constructor to maintain the hierarchy and guarantee it. They assume that if you don't explicitly create the parent object FIRST (like if you forgot about it), they will do it implicitly for you.

    This check is done during compilation. But I'm not sure what would happen on runtime, what kind of runtime error we would get, IF Java doesn't throw a compile-error when we explicitly try to execute a base constructor from within a subclass's constructor in the middle of its body and not from the very first line ...

    0 讨论(0)
  • 2020-11-21 23:26

    That's because your constructor depends on other constructors. To your constructor work correctly its necessary to other constructor works correctly which is dependent. That's why its necessary to check dependent constructors first which called by either this() or super() in your constructor. If other constructors which called by either this() or super() have a problem so whats point execute other statements because all will fail if called constructor fails.

    0 讨论(0)
  • 2020-11-21 23:26

    The main goal of adding the super() in the sub-class constructors is that the main job of the compiler is to make a direct or indirect connection of all the classes with the Object class that's why the compiler checks if we have provided the super(parameterized) then compiler doesn't take any responsibility. so that all the instance member gets initialized from Object to the sub - classes.

    0 讨论(0)
  • 2020-11-21 23:27

    You can use anonymous initializer blocks to initialize fields in the child before calling it's constructor. This example will demonstrate :

    public class Test {
        public static void main(String[] args) {
            new Child();
        }
    }
    
    class Parent {
        public Parent() {
            System.out.println("In parent");
        }
    }
    
    class Child extends Parent {
    
        {
            System.out.println("In initializer");
        }
    
        public Child() {
            super();
            System.out.println("In child");
        }
    }
    

    This will output :

    In parent
    In initializer
    In child

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