修饰类
final 修饰类的时候代表这个类是不可以被扩展继承的,例如 JDK 里面的 String 类。
修饰方法
final 修饰方法的时候代表这个方法不能被子类重写。
修饰变量
final 修饰变量的时候,这个变量一旦被赋值就不能再次被赋值。
缓存
final 变量会被缓存在寄存器中而不需要去主从获取,而非 final 变量的则需要去主存重新加载。
线程可见性
类的 final 域在编译器层面会保证在类的构造器运行结束之前一定要初始化完成,同时 Java 内存模型会保证对象实例化后它的 final 域对其他线程是可见的,然而非 final 域并没有这种待遇。例如如下代码:
public class FinalFiled {
final int x;
int y;
static FinalFiled f;
public FinalFiled() {
x = 100;
y = 100;
}
static void writer() {
f = new FinalFiled();
}
static void reader() {
if (f != null) {
int i = f.x; // 保证此时一定是 100
int j = f.y; // 有可能此时还是 0
}
}
}
当线程 A 执行了 writer 方法后,有线程 B 会进入 f != null 成立条件的代码块,此时由于变量 x 是 final 修饰的,JMM 会保证 x 此时的值一定是 100,而 y 是非 final 的,则有可能此时 y 的值还是 0,并未被初始化。
安全性
String 类的安全性也得益于恰到好处的使用了大量的 final 域,大家可以去翻翻 String 类的源码。我们来举个例子,假设有线程 A 执行如下代码段:
Global.flag = "/001/002".substring(4);
又有线程 B 执行如下代码段:
String myS = Global.flag;
if (myS.equals("/001"))System.out.println(myS);
如果没有 final 域的可见性保证,那么线程 B 在执行的时候有可能看到的字符串的长度可能仍然是 0。当有了 final 域的可见性保证,就可以让并发程序正确的执行。也使得 String 类成为名副其实的不可变安全类。
以上即为昨天的问题的答案,小伙伴们对这个答案是否满意呢?欢迎留言和我讨论。
又要到年末了,你是不是又悄咪咪的开始看机会啦。为了广大小伙伴能充足电量,能顺利通过 BAT 的面试官无情三连炮,我特意推出大型刷题节目。每天一道题目,第二天给答案,前一天给小伙伴们独立思考的机会。

本文探讨了Java中final关键字的用法,包括修饰类、方法和变量的影响。final变量在缓存、线程可见性和安全性方面有特殊作用,如确保线程安全和不可变性。了解final的应用对于优化并发程序和提升代码安全性至关重要。

被折叠的 条评论
为什么被折叠?



