现在的位置: 首页 > 综合 > 正文

你用过Java 中的 final 关键字吗?有哪些作用?

2020年02月19日 综合 ⁄ 共 991字 ⁄ 字号 评论关闭

  你用过 Java 中的 final 关键字吗?它有哪些作用?这也是出镜率极高的题目哦。

  1. final 修饰类的时候代表这个类是不可以被扩展继承的,例如 JDK 里面的 String 类。

  2. final 修饰方法的时候代表这个方法不能被子类重写。

  3. final 修饰变量的时候代表这个变量一旦被赋值就不能再次被赋值。

  想必上面这三点是大家所熟知的,但是下面这 2 点你想到了吗?

  缓存

  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 类成为名副其实不可变安全类。

抱歉!评论已关闭.