2012-01-31 147 views
24

Java语言文档中提到“如果原始类型或字符串被定义为常量,并且该值在编译时已知,则编译器会用代码中的值替换常量名称。被称为编译时常量。“编译时间常量和变量

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

private final int x = 10; 

然后,编译器会用文字“10”替换代码“x”的每次出现。 但表示假设不变与在运行时间值初始化,

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. 没有final是一个变量,不会被视为常量。

我的理解是否正确?

+5

约2点你就错了! final int a = 1; a是编译时间常量。 final int b; b = 1; b不是 – landry 2013-03-13 03:42:38

回答

41

编译时间常数必须:

  • 宣告最终
  • 原始或字符串
  • 声明
  • 与常量表达式初始化内初始化

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

第二个问题private int y = 10;不是常数(在这种情况下是非最终的),因此优化器不能确定该值在将来不会改变。所以它不能像恒定的价值那样优化它。答案是:不,它不像编译时间常量那样处理。

+2

JLS定义常量表达式:http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28 – 2015-04-03 10:10:46

+1

一个例子以清除疑问:最终诠释一个= 1;是一个编译时间常量,但最终是int a; A = 2;是不是 – 2016-07-01 02:44:56

+0

我认为它可以在声明内或在构造函数中初始化 – 2017-03-03 06:25:34

1

可能一个非常小性能下降一些private final int x = getX();因为这将涉及至少一个方法调用(除了这个事实,这不是一个编译时间常数),但正如你说,这将是可以忽略所以为什么要麻烦?

至于第二个问题:y不是最终的,因此它不是一个编译时间常量,因为它可能会在运行时更改。

1

private final int x = getX(); 将在第一次声明对象时被调用。性能“下降”将取决于getX(),但这不是造成某些瓶颈的事情。

2

final关键字意味着变量将被初始化一次且仅一次。一个真正的不断需要被宣布为static。 所以,你的例子没有一个被编译器视为常量。尽管如此,final关键字告诉你(和编译器)你的变量只会被初始化一次(在构造函数中或字面上)。 如果您需要在编译时分配它们的值,那么您的字段必须是静态的。

性能不是真的受到影响,但要记住原始类型是不可变的,一旦你创建了一个,它将在内存中保存该值,直到垃圾收集器将其删除。 因此,如果你有一个变量y = 1;,然后你在内存中将它改为y = 2;,JVM将有两个值,但你的变量将“指向”后者。

private int y = 10; //这里y不是最终的

被编译器视为编译时间常量的方式?

不。这是一个实例变量,创建并初始化了一个在运行时使用的实例变量。

0

根据JLS,没有要求“常量变量”应该是静态的。

所以“常量变量”可能是静态或非静态的(实例变量)。

但JLS规定一个变量是一个“常数变量”的一些其他要求(除了是刚决赛):

  • 仅为String或基本
  • 初始化内嵌而已,因为它是最后的,和空白最终不允许
  • 用“常量表达式”初始化=“编译时常量表达式”(见下文JLS引号)

4.12.4. final Variables (JLS)

常量变量是与一个常量表达式(§15.28)初始化基本类型或String类型的最终变量。

15.28. Constant Expressions

编译时间常量表达式是表示原始类型或字符串的值 不突然完成并是 仅使用由以下的表达式:

原始类型和字符串类型的文字(§3.10.1, §3.10.2,§3.10.3,§3.10.4,§3.10.5)

强制转换为原始类型和强制转换为串类型(§15.16)

一元运算符+, - , - 和! (但不是++或 - )(§15.15.3, §15.15.4,§15.15.5,§15.15.6)

乘法运算符*,/,和%(§15.17)

加法运算符+和 - (§15.18)

移位运算符< <,>>和>>>(§15.19)

关系运算符<,< =,>,和> = (但不是实例) (§15.20)

相等运算符==和!=(§15.21)

位运算符和逻辑运算符&,^和| (§15.22)

条件运算符& &和条件运算符|| (§15.23,§15.24)

三元条件运算? :(§15.25)

括号的表达式(§15.8.5),其包含的表达式是 常量表达式。

简单的名称(§6.5.6.1)引用常量变量(§4.12.4)。

合格的名称(§6.5.6.2)的形式类型名的。 引用常量变量(§4.12.4)的标识符。