Reputation: 3831
This is an extension of question: Order of the initialization in Java
so in the code block:
public class Point {
int y = getX();
int x = 42;
int getX() {
return x;
}
public static void main (String s[]) {
Point p = new Point();
System.out.println(p.x + "," + p.y);
}
}
It outputs 42,0
While the above question was answered by describing the behavior of the Java compiler and runtime, it is still bugging me why the compiler does not bake the initial value of x (42) into the bytecode? I know the values of static variables get embedded into the bytecode since they are class level variables and they dont take up any space in the object memory, but doesn't it make sense to also embed any initial values for class level non-static variables also into the bytecode? That way, the code above will be more in-line with expected behavior, and the instantiation of the object will be quicker I am guessing (since the memory assigned to x will immediately contain 42 hence saving time in parsing the initialization line in the class every time an object of class Point is created)
I suspect this might have something to do with the tradeoffs between class bytecode size, object initialization efficiency, and compile time efficiency.
I am hoping someone with deep knowledge on Java compiler/runtime can throw some light on this. Knowing how a framework works internally always helps us write better code :-)
Upvotes: 0
Views: 390
Reputation: 269857
I think that you are misunderstanding what happens with constants, and why.
Compile-time constants can be in-lined, but in general, static variables are not. A compile-time constant is defined in the specification, but simply put, it's a value of primitive type that is known at compile time. There are many static variables that are initialized with expressions that aren't compile-time constants.
In this case, Point
and getX()
are not final, so the result of getX()
is unknown at compile-time. How could it possibly be in-lined when a subclass could override it and return a different value?
Upvotes: 3
Reputation: 198471
It's not a question of efficiency; it's a question of having sensible semantics.
The Java designers wanted the behavior of initialization to be the same whether x
is defined to be 42
or to be getFortyTwo()
, because if that behavior is different, then that leads to all kinds of ways to unintentionally shoot yourself in the foot. So they specified in the JLS which order field initialization occurs in, and that order is independent of whether x
is a constant or a method call or a potato. (For reference, it's the order that you declare the fields in -- so if you reversed the order of x
and y
in your class, y
would be set to 42.)
Frankly, I would bet that the compiler bakes the assignment y = 0
into the constructor, because the JLS's semantics require that y = 0
based on this code.
Upvotes: 6
Reputation: 1503290
While the above question was answered by describing the behavior of the Java compiler and runtime, it is still bugging me why the compiler does not bake the initial value of x (42) into the bytecode?
Imagine if you later changed this:
int x = 42;
to this:
int x = getInitialValueForX();
Would you really want that to completely change the behaviour?
If x
is really just a constant, then make it static final
and it will be inlined. As it is, if a variable isn't final and isn't static then I don't see why it should be treated as a constant even though the initial value happens to be a constant at the moment.
Upvotes: 3