DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations

Trending

  • Implementing RBAC in Quarkus
  • Mainframe Development for the "No Mainframe" Generation
  • Merge GraphQL Schemas Using Apollo Server and Koa
  • HashMap Performance Improvements in Java 8
  1. DZone
  2. Coding
  3. Languages
  4. Java Object Initialization Order - Know your JLS!

Java Object Initialization Order - Know your JLS!

Daniel Schneller user avatar by
Daniel Schneller
·
Jul. 19, 10 · Interview
Like (0)
Save
Tweet
Share
23.49K Views

Join the DZone community and get the full member experience.

Join For Free

Recently I came across an interesting problem whose solution eluded me at first glance. Consider these three classes:

package com.ds.test;

public class Upper {
String upperString;

public Upper() {
Initializer.initialize(this);
}
}
package com.ds.test;

public class Lower extends Upper {

String lowerString = null;

public Lower() {
super();
System.out.println("Upper: " + upperString);
System.out.println("Lower: " + lowerString);
}

public static void main(final String[] args) {
new Lower();
}
}

package com.ds.test;
public class Initializer {
static void initialize(final Upper anUpper) {
if (anUpper instanceof Lower) {
Lower lower = (Lower) anUpper;
lower.lowerString = "lowerInited";
}
anUpper.upperString = "upperInited";
}
}

What output is to be expected from running the Lower class? In this very reduced example it is much easier to get a view of the whole situation - in reality where this occurred there was a lot more code to distract one's attention...

Anyway, this is what the output looks like:

Upper:  upperInited
Lower: null;

While the little example uses Strings, the real code of Initializer had a delegate object registered with the equivalent of the Lower class - at least that was the intention. For some reason however did this not work when running the application. Instead, the default path was taken - the one for the delegate object being not set (null).

Now, change the code of Lower slightly:

package com.ds.test;

public class Lower extends Upper {

String lowerString;

public Lower() {
super();
System.out.println("Upper: " + upperString);
System.out.println("Lower: " + lowerString);
}

public static void main(final String[] args) {
new Lower();
}
}

The output is now:

Upper:  upperInited
Lower: lowerInited

Notice the difference in the code?

Yes, the lowerString field is no longer explicitly set to null. Why would this make a difference? Isn't the default value for reference type fields (such as String here) null anyway? Of course, it is. However it turns out that this tiny little change - which apparently would not change the code's behavior in any way - makes this thing fly or not fly.

So what is going on? It becomes clear when looking at the initialization order:

  1. main() calls the Lower constructor.
  2. An instance of Lower is prepared. That means, all fields are created and populated with default values, i. e. null for reference types, false for booleans and so on. At this time, any inline assignments to the fields have not taken place!
  3. The super-constructor is called. This is mandated by the language spec. So, before anything else happens, Upper's constructor is called.
  4. The Upper constructor runs and hands a reference to the freshly created instance to the Initializer.initialize() method.
  5. The Initializer attaches new Strings to both fields. It does so by using a somewhat dirty instanceof check - not a particularly good design pattern, but possible, nevertheless. Once that has happened, both the upperString lowerString references are no longer null.
  6. The Initializer.initialize() call finishes, as does the Upper constructor.
  7. Now it becomes interesting: Construction of the Lower instance continues. Assuming there is no explicit =null assignment in the lowerString field declaration, the Lower constructor resumes execution and prints out the two Strings that are attached to the fields.
    However, if there is an explicit assignment to null, execution has a slightly different flow: Just when the super constructor is done, any variable initializers are executed (see section 12.5 of the Java Language Spec), before the rest of the constructor is run. In this case the String reference that was previously assigned to lowerString is not overwritten with null again! Only then does the rest of the constructor continue execution, now printing lowerString: null.

Apart from being a nice example for why it is handy to be aware of some of the minutiae of object creation (or knowing where to look in the JLS, printed or online) this shows why it is a bad idea to write the Initializer like this. It should not be aware of Upper's subclasses at all! Instead, if for some reason initialization of certain fields cannot be done in the Lower class itself, it will just require its own variant of some sort of initialization helper. In that case, it would really make no difference if you used String lowerString; or String lowerString = null; - just as it should be.

 

From http://www.danielschneller.com/2010/07/java-object-initialization-order-know.html

Object (computer science) Java (programming language)

Opinions expressed by DZone contributors are their own.

Trending

  • Implementing RBAC in Quarkus
  • Mainframe Development for the "No Mainframe" Generation
  • Merge GraphQL Schemas Using Apollo Server and Koa
  • HashMap Performance Improvements in Java 8

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: