• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

Inheritance and block initialization

 
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello everyone!

I am struggling to understand the output of the following code:





Output: 13245

Firstly, the classes are loaded so any static block will be executed, in this case 1 is printed.

Secondly, when the Dog() object is created, the initialization of the superclass happens first, so the initializer block of Car prints 3.

Now I am confused as to why 2 gets printed before 4? If 2 is printed before 4 it means the constructor of class Dog has been called which in turn calls the super constructor. But as we know the initializer block is executed before the constructor block. Please help!

Thanks in advance for your replies and comments!
 
Saloon Keeper
Posts: 15727
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to CodeRanch!

The superclass needs to be completely initialized before the subclass can start initializing itself. That means that the constructor of the superclass finishes running before initializer blocks of the subclass are run.

So yes, within a single class definition, initializers are run before constructors. But constructors of superclasses run before initializers of subclasses.
 
Marshal
Posts: 79956
396
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to the Ranch (again)

Well done using the code button, but you didn't quite use it in the right place. Don't worry; I have corrected that and doesn't the code look better now In future please separate your constructors and initialisers by single empty lines; it makes it much easier to read.
You can read about initialisers in the Java® Language Specification (=JLS). It doesn't say much about the order of execution however. The following example, however, shows it being added to the constructor:-The lines starting 5: and 7: are copied from the (instance) initialiser, seen in the original code:-
 
Campbell Ritchie
Marshal
Posts: 79956
396
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

A few minutes ago, I wrote:. . . The following example, however, shows it being added to the constructor . . .

Since the JLS doesn't explicitly specify that behaviour, it might change in future releases or versions.
 
Master Rancher
Posts: 5060
81
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The JLS is quite specific about when each of these parts run.  See JLS 12.5:

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

2. If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.

3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.

4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.

5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.


Step 4 makes clear that instance initializers and instance variable initializers are run in the order they occur textually in the source code, and step 5 makes it clear that the body of the constructor runs after step 4 completes.

Now, when you look at the generated bytecode with javap, you're dealing with how it's compiled.  Some details of that are unspecified, as long as the resulting code executes according to the JLS.  But it's worth noting that, at the bytecode level, the JVM doesn't have a notion of any difference between instance initializers, instance variable initializers, and constructor bodies. It only has an instruction to create a new class instance, completely blank with all fields set to default values, and it has instance initialization methods, which necessarily contain everything else, whether it came from initializers, variable initializer, or constructor body - including those from a superclass.  So when javap shows that some code is part of "Foo()", that's really shorthand for the method whose name is really "<init>" with zero arguments, which can include code from multiple sources.
 
Rajat Bhatt
Greenhorn
Posts: 5
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, I think I get it now.

Thanks everyone!
 
Campbell Ritchie
Marshal
Posts: 79956
396
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike Simmons wrote:The JLS is quite specific about when each of these parts run. . . .

Thank you; I had forgotten about that section.

that's really shorthand for the method whose name is really "<init>" . . . .

Constructors aren't methods, but they are replaced by the method “<init>” in the bytecode. As you say, copying the initialisers into “<init>” is how it is implemented, and implementation details are allowed to change. And you should be able to do all your programming without knowing anything about such implementation details.
 
Saloon Keeper
Posts: 28319
210
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To refine Campbell's explanation, all of the extra-method code (initializer statements and blocks) are scooped up by the compiler and placed in a "ghost" method (<init>).

This method cannot be explicitly invoked (it doesn't have a syntactically legal name, for one thing), however, it's invoked after any superclass construction (if any) and effectively as the first statement of each of the current class's constructors. Or if no constructor methods are invoked, before the class being constructed is handled to the general application logic.
 
Mike Simmons
Master Rancher
Posts: 5060
81
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:This method cannot be explicitly invoked (it doesn't have a syntactically legal name, for one thing)


It can't be invoked from Java code, the .java files we normally look at.  It can be invoked just fine from JVM bytecode in .class files, however.

Tim Holloway wrote:however, it's invoked after any superclass construction (if any)


The <init> method of the superclass is explicitly invoked at the beginning of the <init> method of the subclass.  So it's part of the compiler's job to generate bytecode to make sure the super constructor is called at the appropriate place.
 
You save more money with a clothesline than dozens of light bulb purchases. Tiny ad:
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic