Compile-time constants and variables
Asked Answered
T

8

54

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:

  1. final static means compile-time constant
  2. just final means it's a constant but is initialized at run-time
  3. just static means initialized at run-time
  4. without final is a variable and wouldn't be treated as constant.

Is my understanding correct?

Tit answered 31/1, 2012 at 16:18 Comment(1)
about point 2. You are wrong! final int a =1; a is compile time constant. final int b; b =1; b is notDucharme
A
66

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.

Alden answered 31/1, 2012 at 16:21 Comment(10)
JLS defining constant expression: docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28Whensoever
one more example to clear the doubt : final int a=1; is a compile time constant but final int a; a=2; is notDulcine
i think it can be initialised within declaration or within constuctorAranda
private final int x = getX(); is a constant, but not a compile time constant, isn 't it?Grasso
@KorayTugay You are just playing with the terminology. In Java world we use "final", for things that are not going to change. And "constant" (or "compile-time constant") for something that is constant. This might be hard to understand for someone who don't have Java experience, and comes from other languages, but... you have to admit, that "final" and "constant" is something different. docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.4 "A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28)."Alden
I do not think you can say "constant" (or "compile-time constant"), those are 2 different things.Grasso
private final int x is a constant, it is just not a compile-time constant..Grasso
@KorayTugay compile-time constant and constant are synonymous in Java. If a final variable does not meet the criteria to be considered a constant it is referred to as a final variable. You will not find the term compile-time constant in the JLS. msi addressed this in his comment above, and I added it to my answer below as well.Brucine
case only takes constant expression, so only constant or constant expression will compile. e.g. legal - final int i = 2; switch(x) { case i:case i+2: }Luggage
And what about "Effectively final" variable. Now the compiler/parser is smart enough to detect that a variable is never reassign, and treat it like a constant during compilation.Marceau
B
7

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.

Brucine answered 19/4, 2018 at 23:51 Comment(0)
T
3

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).

15.28. Constant Expressions

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).

Thermoelectrometer answered 26/1, 2018 at 11:31 Comment(0)
N
1

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.

Nerissa answered 31/1, 2012 at 16:21 Comment(0)
V
1

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.

Volgograd answered 31/1, 2012 at 17:2 Comment(0)
N
1

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;
}
Nonconformity answered 8/7, 2020 at 10:43 Comment(0)
R
0

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.

Roofer answered 31/1, 2012 at 16:21 Comment(0)
S
0

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';

Please check this explanation

Sandpaper answered 7/1, 2020 at 9:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.