编译时常量和变量

Java语言文档说:

如果将基元类型或字符串定义为常量,并且该值在编译时已知,则编译器会将代码中所有位置的常量名称替换为其值。这称为编译时常量。

我的理解是,如果我们有一段代码:

private final int x = 10;

然后,编译器会将代码中出现的 每个匹配项替换为文字 。x10


但假设该常量在运行时初始化:

private final int x = getX(); // here getX() returns an integer value at run-time.

与编译时常量相比,性能是否会下降(无论可以忽略不计)?


另一个问题是下面的代码行是否:

private int y = 10; // here y is not final

编译器以与编译时常量相同的方式处理?


最后,我从答案中了解到的是:

  1. final static表示编译时常量
  2. 只是意味着它是一个常量,但在运行时初始化final
  3. 只是意味着在运行时初始化static
  4. without 是一个变量,不会被视为常量。final

我的理解是否正确?


答案 1

编译时常量必须为:

  • 宣布最终
  • 基元或字符串
  • 在声明中初始化
  • 使用常量表达式初始化

所以不是恒定的。private final int x = getX();

对于第二个问题不是常量(在本例中不是最终的),因此优化程序无法确定该值将来不会更改。因此,它不能像恒定值那样优化它。答案是:不,它的处理方式与编译时间常数不同。private int y = 10;


答案 2

JLS在变量和常量之间做了以下区分:final

final变量

可以声明变量 。一个变量只能赋给一次。如果将变量赋值给,则为编译时错误,除非在赋值之前立即明确未赋值(§16(定赋值))。finalfinalfinal

分配变量后,它始终包含相同的值。如果变量包含对对象的引用,则对象的状态可以通过对该对象的操作进行更改,但该变量将始终引用同一对象。这也适用于数组,因为数组是对象;如果变量包含对数组的引用,则数组的组件可以通过对数组的操作进行更改,但变量将始终引用同一数组。finalfinalfinal

空白 final 是其声明缺少初始值设定项的变量。final

常数

常量变量是使用常量表达式 (§15.28) 初始化的基元类型或类型的变量。finalString

从这个定义中,我们可以辨别出常量必须是:

  • 宣布final
  • 基元类型或类型String
  • 在其声明中初始化(不是空白的最终值))
  • 使用常量表达式初始化

编译时常量呢?

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

如果变量不符合上述被视为常量的条件,则从技术上讲,它应称为变量。finalfinal


推荐