Compile-time constants and variables
JavaPerformanceConstantsFinalCompile Time-ConstantJava Problem Overview
The Java language documentation says:
> If a primitive type or a string is defined as a constant and the value > is known at compile time, the compiler replaces the constant name > everywhere in the code with its value. This is called a compile-time > constant.
My understanding is if we have a piece of code:
private final int x = 10;
Then, the compiler will replace every occurrence of x
in the code with literal 10
.
But suppose the constant is initialized at run-time:
private final int x = getX(); // here getX() returns an integer value at run-time.
Will there be any performance drop (howsoever negligible it may be) compared to the compile-time constant?
Another question is whether the below line of code:
private int y = 10; // here y is not final
is treated in same way as compile-time constant by the compiler?
Finally, what I understand from the answers are:
final static
means compile-time constant- just
final
means it's a constant but is initialized at run-time - just
static
means initialized at run-time - without
final
is a variable and wouldn't be treated as constant.
Is my understanding correct?
Java Solutions
Solution 1 - Java
Compile time constant must be:
- declared final
- primitive or String
- initialized within declaration
- initialized with constant expression
So private final int x = getX();
is not constant.
To the second question private int y = 10;
is not constant (non-final in this case), so optimizer cannot be sure that the value would not change in the future. So it cannot optimize it as good as constant value. The answer is: No, it is not treated the same way as compile time constant.
Solution 2 - Java
The JLS makes the following distinctions between final
variables and constants:
###final
variables
> A variable can be declared final
. A final
variable may only be
> assigned to once. It is a compile-time error if a final
variable is
> assigned to unless it is definitely unassigned immediately prior to
> the assignment (§16 (Definite Assignment)).
>
> Once a final
variable has been assigned, it always contains the same
> value. If a final
variable holds a reference to an object, then the
> state of the object may be changed by operations on the object, but
> the variable will always refer to the same object. This applies also
> to arrays, because arrays are objects; if a final
variable holds a
> reference to an array, then the components of the array may be changed
> by operations on the array, but the variable will always refer to the
> same array.
>
> A blank final
is a final
variable whose declaration lacks an
> initializer.
###constants
> A constant variable is a final
variable of primitive type or type
> String
that is initialized with a constant expression (§15.28).
From this definition, we can discern that a constant must be:
- declared
final
- of primitive type or type
String
- initialized within its declaration (not a blank
final
) - initialized with a constant expression
###What about compile-time constants?
The JLS does not contain the phrase compile-time constant. However, programmers often use the terms compile-time constant and constant interchangeably.
If a final
variable does not meet the criteria outlined above to be considered a constant, it should technically be referred to as a final
variable.
Solution 3 - Java
According to JLS, there is no requirement that "constant variable" should be static.
So "constant variable" maybe static or non-static (instance variable).
But JLS imposes some other requirements for a variable to be a "constant variable" (besides being just final):
- being only String or primitive
- initialized inline only, because it is final, and blank final is not allowed
- initialized with "constant expression" = "compile-time constant expression" (see JLS quote below)
4.12.4. final Variables (JLS) > A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).
> A compile-time constant expression is an expression denoting a value > of primitive type or a String that does not complete abruptly and is > composed using only the following: > > Literals of primitive type and literals of type String (§3.10.1, > §3.10.2, §3.10.3, §3.10.4, §3.10.5) > > Casts to primitive types and casts to type String (§15.16) > > The unary operators +, -, ~, and ! (but not ++ or --) (§15.15.3, > §15.15.4, §15.15.5, §15.15.6) > > The multiplicative operators *, /, and % (§15.17) > > The additive operators + and - (§15.18) > > The shift operators <<, >>, and >>> (§15.19) > > The relational operators <, <=, >, and >= (but not instanceof) > (§15.20) > > The equality operators == and != (§15.21) > > The bitwise and logical operators &, ^, and | (§15.22) > > The conditional-and operator && and the conditional-or operator || > (§15.23, §15.24) > > The ternary conditional operator ? : (§15.25) > > Parenthesized expressions (§15.8.5) whose contained expression is a > constant expression. > > Simple names (§6.5.6.1) that refer to constant variables (§4.12.4). > > Qualified names (§6.5.6.2) of the form TypeName . Identifier that > refer to constant variables (§4.12.4).
Solution 4 - Java
There might be a really small performance drop on some machines for private final int x = getX();
since that would involve at least one method call (besides the fact that this isn't a compile-time constant) but as you said, it would be negligible so why bother?
As for the second question: y
isn't final and thus is not a compile time constant, since it might change at runtime.
Solution 5 - Java
The final
keyword means that a variable will be initialized once and only once. A real constant need to be declared static
as well.
So, none of your examples are treated as constants by the compiler. Nevertheless, the final keyword tells you (and to the compiler) that your variables will be initialized once only (in the constructor or literally).
If you need their values assigned at compile time your fields must be static.
Performance is not really that affected, but have in mind that primitive types are immutable, once you have created one it will hold that value in memory until the garbage collector removes it.
So, if you have a variable y = 1;
and then you change it to y = 2;
in memory the JVM will have both values, but your variable will "point" to the latter.
> private int y = 10; // here y is not final
> is treated in same way as compile time constant by the compiler ?
No. This is an instance variable, created, initialized an used at runtime.
Solution 6 - Java
Just keep in mind that in the following code, x is not compile time constant:
public static void main(String[] args) {
final int x;
x= 5;
}
Solution 7 - Java
private final int x = getX();
Will be called the first time your object is declared. The performance "drop" will depend on getX()
but that's not the kind of things to create some bottleneck.
Solution 8 - Java
Simply speaking while compilation the compiler replaces the reference with the actual value specified, instead of using the reference parameter.
public static void main(String[] args) {
final int x = 5;
}
ie. while compilation the complier take the initialised value of 5 directly for compliation than using the reference variable 'x';