问题
I understood what a compile time constant rule is from Compile-time constants and variables.
- declared as final
- have a primitive or String type
- initialized at the same time as the declaration
- initialized with constant expression
final int x = 5;
But I fail to understand why below code doesn't:
final int x;
x = 5;
The only difference is of third point above. How initialization on different line instead of same line makes a difference.
回答1:
Case 1 final int x = 5;
public static void main(String[] args) {
final int x = 5;
}
The bytecode generated is:
public static main([Ljava/lang/String;)V
L0
LINENUMBER 3 L0
ICONST_5
ISTORE 1
L1
LINENUMBER 4 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
LOCALVARIABLE x I L1 L2 1
MAXSTACK = 1
MAXLOCALS = 2
Case 2 final int x; x = 5;
public static void main(String[] args) {
final int x;
x = 5;
}
The bytecode generated is:
public static main([Ljava/lang/String;)V
L0
LINENUMBER 4 L0
ICONST_5
ISTORE 1
L1
LINENUMBER 5 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
LOCALVARIABLE x I L1 L2 1
MAXSTACK = 1
MAXLOCALS = 2
As you can see there is no difference between the 2 cases, except for the line numbers.
In fact in an ide such as InteliJ you will see the prompt (as a light bulb) to join the 2 lines of case 2, to 1 line like case 1.
If you read all the answers and comments in the link you provided,
you will be more confused than wiser about this.
It's all about terminology and in this case not documented terminology.
This is an excerpt of one of the answers in that link:
The JLS does not contain the phrase compile-time constant.
However, programmers often use the terms compile-time constant and constant interchangeably.
Now for the case of how the compiler uses the 2 cases.
If you add this line at the end of both methods:
System.out.println(x);
the bytecode generated is:
for case 1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ICONST_5
INVOKEVIRTUAL java/io/PrintStream.println (I)V
and for case 2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ILOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (I)V
There is a difference in the 2nd case: ILOAD 1
instead of ICONST_5
.
Meaning in the 1st case x
was replaced by 5 and in the 2nd case it was not and the value of x
was recalled (loaded) to execute the statement.
回答2:
From JLS Sec 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).
If the variable is declared without being initialized, it is by definition not a constant variable, even if the value you eventually assign to it is a constant expression.
来源:https://stackoverflow.com/questions/53897620/compile-time-constant