一次性局部变量是 final 是什么意思?

Rya*_*rel 2 java

在现有代码库中工作时,我遇到了类似的事情。

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。有什么理由声明DAYfinal?它的范围仅限于此方法,并且仅在其中使用一次。它没有伤害任何东西,但我觉得它看起来很奇怪,想问问这个变量被声明是否有任何意义final

kay*_*ya3 7

是的,这样做是有道理的。声明时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文件稍小,如果不多次调用该方法,则性能优势很小。