Explicit Java constructor call and instance initializer

In Java tutorials - Field Initialization , contains a description of the instance initialization elements (Instance Initializer):

The Java compiler copies initialization blocks to each constructor . Therefore, this approach can be used to share a block of code between multiple constructors.

If the paraphrase is correct, for the following codes:

public class ConstructorTest { public static void main(String[] args) { Child c = new Child(); } } class Parent { Parent() { System.out.println("Parent non-argument Constructor"); } } class Child extends Parent { { System.out.println("Child Instance Initialization Block"); } Child() { this(2); System.out.println("Child no-argument Constructor"); } Child(int i) { this(10, i); System.out.println("Child 1-argument Constructor"); } Child(int i, int j) { System.out.println("Child 2-argument Constructor"); } } 

The output should be:

 Parent non-parm Constructor Child Instance Initialization Block Child 2-argument Constructor Child Instance Initialization Block Child 1-argument Constructor Child Instance Initialization Block Child no-argument Constructor 

But in fact, the conclusion:

 Parent non-argument Constructor Child Instance Initialization Block Child 2-argument Constructor Child 1-argument Constructor Child no-argument Constructor 

Did I misunderstand the meaning of this sentence, or is the description not accurate enough?

And one more doubt in the explicit constructor call:

Based on two basic principles:

  • If present, calling another constructor should be the first line in the constructor.
  • Inside the constructor, use this () to call another constructor, use super () to call the direct superclass. The corresponding constructor.

Is this using MEANS with this () inside the constructor of the subclass, will it be implicit to remove the default call to the constructor without arguments to the superclass?

Thanks for the answer.

+4
source share
3 answers

EDIT: It turns out JLS is accurate, although it's hard to read. All this is described in detail in section 12.5 :

Before the result is a reference to the newly created object, the specified constructor is processed to initialize the new object using the following procedure:

  • Assign constructor arguments to the newly created parameter variables for this constructor call.

  • If this constructor starts by explicitly calling the constructor (ยง8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process the constructor call recursively using these five steps. If the constructor call terminates abruptly, then this procedure terminates abruptly for the same reason; otherwise, go to step 5 .

  • This constructor does not start by explicitly calling the constructor of another constructor in the same class (using this). If this constructor belongs to a class other than Object, then this constructor will start by explicitly or implicitly calling the constructor of the superclass (using super). Evaluate the arguments and handle the call to the superclass constructor recursively using these five steps. If the constructor call terminates abruptly, then this procedure terminates abruptly for the same reason. Otherwise, go to step 4.

  • Run instance initializers and instance variable initializers for this class, assigning the initializer values โ€‹โ€‹of the instance variable to the corresponding instance variables in the order from left to right, in which they are displayed in text form in the source code for the class. If the execution of any of these initializers results in an exception, then no new initializers are processed, and this procedure terminates abruptly with the same exception. Otherwise, go to step 5.

  • Run the rest of the body of this constructor. If this execution completes abruptly, then this procedure terminates abruptly for the same reason. Otherwise, this procedure is performed normally.

Pay attention to the highlighted part - the chain constructor is executed, and then we will skip step 4, which will execute the instance initializer.

The reality is that instance initializers and fields are executed only once, as you can find out from your output.

Informally, I believe that it is accurate to describe the procedure as follows:

  • Keep the chain constructors inside the same class ( this(...) ) until you reach the body of the constructor, which does not start with this .
  • Run the corresponding super constructor
  • Run instance variable initializers and instance initializers
  • Run the body of the "innermost" constructor
  • Keep popping the stack of constructor bodies until you finish the entry constructor

Is this using MEANS with this () inside the constructor of the subclass, will it be implicit to remove the default call to the constructor without arguments to the superclass?

Yes. Somewhere in your constructor chain inside the class, you are guaranteed to get a constructor that calls super implicitly or explicitly. This is the only superclass constructor called.

EDIT: Please note that the tutorial you provided is clearly incorrect.

Class Example:

 public class Test {  {    System.out.println("Foo");  }    public Test() {  }    public Test(int i)  {    this();  } } 

Exiting javap -c :

 public class Test { public Test(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>": ()V 4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 7: ldc #3 // String Foo 9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 12: return public Test(int); Code: 0: aload_0 1: invokespecial #5 // Method "<init>":()V 4: return } 

As you can see, the constructor for Test(int) does not have code for the instance constructor compiled in it.

In principle, only constructors that directly call superclass constructors have instance initializer code in them. All other constructors will cause the instance initializer code to be executed through the constructor, which, of course, calls the superclass constructor.

+5
source

Initialization blocks are launched only once when you instantiate an object of a class (using any constructor <= here is your doubt). Static initialization blocks run only once when the class is loaded by the class loader.

Is this using MEANS with this () in the constructor of the subclass, will it be implied to remove the default call to the constructor with no superclass arguments?

No. this () will call another constructor of the same class, in this case the default constructor (if any). This constructor (one by default) will call super ().

0
source

I think the Java language specification is more accurate: http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.6

The instance initializer declared in the class is executed when the class instance is created.

and in http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.5 steps 4 and 5 describe the result you observed:

4. Run instance initializers and instance variable initializers for this class ...

5. Run the rest of the body of this constructor ...

0
source

Source: https://habr.com/ru/post/1432150/


All Articles