Trick question: What is difference between these:
Sample Code 1
[code lang=”java”]
class FooBar {
private int x = 0;
[/code]
Sample Code 2
[code lang=”java”]
class FooBar {
private int x;
[/code]
Q: What is difference?
I.e. aren’t those pieces of code by definition exactly same, thus it doesn’t matter what you write.
A: There is hidden initialization cost involved, and as additional side issue, also additional initialization order dependency.
What these things do in byte code level is this:
Sample 1:
[code lang=”java”]
class FooBar{
public FooBar {
….
aload_0;
iconst_0;
putField #2; //Field x
return;
}
}
[/code]
Sample 2:
[code lang=”java”]
class FooBar{
public FooBar {
….
return;
}
}
[/code]
And there is the answer. Doing redundant extra initialization COSTS something, namely it costs extra byte code added into end of constructor (Correction: Code is appended right after the return from super constructor, i.e. just before code executed in local constructor, please notice that this this can actually cause even triple initialization of variables; once by JVM, then by explicit initialization added into field definition and third one placed into constructor. And that can be called unoptimal).
And that initialization order side-effect? This means that value of field is overridden in the end of constructor. If there is any call from super class, into method, which tries to initialize one of fields like this:
[code lang=”java”]
class FooBar extends Sample {
@Override
protected void initX() {
x = 100;
}
[/code]
Net result of that is that Sample
will call initX(), and it will set value. However, when control returns into constructor of FooBar
it will OVERRIDE initialized value.
This effects has been seen in real production code, and understanding what is failing is tricky; i.e. requires understanding what such innocent looking, 100% redundant extra initialization is actually causing.
As additional extra, please notice that this same extra boilerplate code is added into every constructor.
….
And that’s why I’m strictly against such redundant initializations; they cause two fold problem, (a) Extra (100% redundant) byte codes executed by JVM, and (b) It breaks 100% completely all lazy initialization getter methods.
Of course, if one is living in laa-laa-land, where CPU cycles are free, then this babbling doesn’t matter. Sadly in real world, CPU cycles are not free, and JVM JIT isn’t magic wand.