I have read other question-answers regarding final instance variables and i came to knew that non-static final instance variables are created in heap for every instance of the class but in java -the complete reference by herbert schildt it is said that :
Variables declared as final do not occupy memory on a per-instance basis .thus, a final variable is essentially a constant
Which is correct?
Advertisement
Answer
The first statement is correct … though limited to final
fields of instances.
The second statement is incorrect.
A final
variable will occupy memory somewhere at runtime. However where that memory is depends on the kind of variable that you declare as final
.
If the variable is a local variable or a method’s formal argument variable, then the memory cell will be on the stack.
If the variable is a non-static field, then the memory cell will be part of an object, and will be in the heap.
If the variable is a static field, then the location of the memory cell will be implementation dependent. (It could be in the heap, or it could be somewhere else.)
It should be noted that some (but not all!) kinds of static final
fields are compile constants, and their values are effectively inlined by the compiler. But even when that happens, there will still be an actual field that occupies a memory cell at runtime, and the contents of that memory cell can be accessed reflectively.
(Indeed, you can even modify a final
field reflectively. When you do that, the behavior is not specified by the JVM spec, and can be rather surprising in some cases.)
Does final variables occupy memory on a per-instance basis?
No, because:
- static variables don’t “occupy memory on a per-instance” whether or not they are
final
. - local variables and parameters can be
final
too, and they don’t “occupy memory on a per-instance”
Can this assumption be made by the compiler if
final
variables are initialized at their declaration itself and allocate memory to it only one time because obviously every instance created will have the same value for that final variable. Is compiler smart enough to do this kind of optimization?
Consider this
public class Test public static test(final int val) { System.out.println(val); } }
Now val
is final
, but its value depends on how you call test
method. That is not known at (javac
) compile time, and typically it is not known to the JIT compiler either. Indeed, assuming that test
is called with different parameters, you can’t directly optimize away the val
memory cell.
The same applies to every case apart from static final
variables that qualify as compile-time constants (as per the JLS definition).
It is theoretically possible that the JIT compiler could see that Test.test
is only ever called with the same constant value, and inline that value into the native code so that no memory cell is needed. However, that optimization has minimal performance benefit, and is unlikely to be applicable in real-life code. So I doubt that it is worth implementing it.
(It is more likely for val
to be optimized away due to inlining the body of test
into its call site. That is a more general optimization an is definitely worthwhile. That may then allow the peephole optimizer to deduce that val
is not needed in the inlined code.)