final 修饰变量时,初衷是告诉编译器:这个变量生而不变,可以可劲儿优化。Java 编译器在 1.5 以前的版本的确优化得很努力,以至于都优化错了。
当然了,在 1.5 以后 Java 内存模型对 final 类型变量的重排进行了约束。现在只要我们提供正确构造函数没有“逸出”,就不会出问题了。

  1. public class TestFinal {
  2. final int a = 20;
  3. }

设置final的值

image.png
发现 final 变量的赋值也会通过 putfield 指令来完成,同样在这条指令之后也会加入写屏障,保证在其它线程读到它的值时不会出现为 0 的情况。

获取final的值

编译的时候就已经将final的值复制一份到使用它的方法中。

  • 如果不加final,对象就会在堆中。
  • 加了final,对象可能在栈中,也可能在常量池中。性能得到了提升。