在现有代码库中工作时,我遇到了类似的事情。
public static int getDatePlusDaysInMillis(int days) {
final int DAY = 24 * 60 * 60 * 1000;
return System.currentTimeMillis() + DAY * days;
}
Run Code Online (Sandbox Code Playgroud)
逻辑本身并不重要,因为我稍微修改了代码,所以我没有复制和粘贴业务代码。
我想引起注意的是final int DAY。有什么理由声明DAY为final?它的范围仅限于此方法,并且仅在其中使用一次。它没有伤害任何东西,但我觉得它看起来很奇怪,想问问这个变量被声明是否有任何意义final。
是的,这样做是有道理的。声明时final,该变量DAY是 Java 语言规范(第4.12.4 节)定义的常量变量:
常量变量是使用常量表达式(第 15.28 节)初始化的原始类型或字符串类型的最终变量。
这意味着一些优化是在编译时完成的,而在未声明变量时则不会完成final。根据您是否使用,我们可以看到不同的字节码final:
public class Test {
public long withoutFinal(int days) {
int DAY = 24 * 60 * 60 * 1000;
return System.currentTimeMillis() + DAY * days;
}
public long withFinal(int days) {
final int DAY = 24 * 60 * 60 * 1000;
return System.currentTimeMillis() + DAY * days;
}
}
Run Code Online (Sandbox Code Playgroud)
编译为:
public long withoutFinal(int);
Code:
0: ldc #2 // int 86400000
2: istore_2
3: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
6: iload_2
7: iload_1
8: imul
9: i2l
10: ladd
11: lreturn
public long withFinal(int);
Code:
0: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
3: ldc #2 // int 86400000
5: iload_1
6: imul
7: i2l
8: ladd
9: lreturn
Run Code Online (Sandbox Code Playgroud)
with 的版本final更短,因为它使用一个ldc(加载常量)操作,而另一个版本使用 a ldc, anistore_2将常量存储到局部变量,并iload_2从该局部变量加载它。
如果多次调用该方法,这种差异可能会在运行时被 JIT 优化掉,但使用final意味着.class文件稍小,如果不多次调用该方法,则性能优势很小。