编译时间常数

时间:2018-12-22 16:57:49

标签: java compiler-errors compilation constants compile-time-constant

我了解Compile-time constants and variables中的编译时间常数规则。

  1. 宣布为最终
  2. 具有基本类型或字符串类型
  3. 与声明同时初始化
  4. 用常量表达式初始化

final int x = 5;

但是我不明白为什么下面的代码没有:

final int x;
x = 5;

唯一的区别是上面的第三点。 在不同的行而不是同一行上进行初始化有何不同?

2 个答案:

答案 0 :(得分:0)

案例1 final int x = 5;

public static void main(String[] args) {
    final int x = 5;
}

生成的字节码为:

  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

案例2 final int x; x = 5;

public static void main(String[] args) {
    final int x;
    x = 5;
}

生成的字节码为:

  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

如您所见,这两种情况之间没有区别,除了行号。

实际上,在诸如InteliJ的想法中,您会看到提示(作为灯泡)将案例2的2行连接到案例1的1行。

如果您在提供的链接中阅读了所有答案和评论,
您会对此感到困惑而不是明智。
这全都与术语有关,在这种情况下,未记录术语。

这是该链接中答案之一的摘录:

  

JLS不包含短语编译时常量。
  但是,程序员经常使用术语编译时常量和常量   可以互换。

现在介绍编译器如何使用这两种情况。
如果您在这两种方法的末尾添加此行:

System.out.println(x);


生成的字节码为:
对于情况1

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ICONST_5
INVOKEVIRTUAL java/io/PrintStream.println (I)V

,对于案例2

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ILOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (I)V

第二种情况有所不同:ILOAD 1而不是ICONST_5
意思是在第一种情况下,x被替换为5,而在第二种情况下,它没有被替换,并且x的值被调用(加载)以执行该语句。

答案 1 :(得分:0)

来自JLS Sec 4.12.4

  

常量变量是原始类型或字符串类型的最终变量,使用常量表达式(第15.28节)初始化。

如果声明变量时未进行初始化,则根据定义,它不是常数变量,即使最终分配给它的值是常数表达式。