一文搞懂 final 关键字
1. final 关键字
final:最终的,被 final 关键字修饰,就不可以改变了。
final 可以修饰:
- 变量:表明该变量是常量,只能被赋值一次。
- 方法:表明该方法是最终方法,不能被重写。不想被别人改写的方法。
- 类:表明该类是最终类,不能被继承。
注:final 不可以修饰构造方法。
2. 使用 final 修饰变量
2.1 编译时常量
Java 编译期常量(compile-time constants)是指在编译时期就能被完全确定并被编译器替换其值的常量,减轻运行时负担。编译期常量:
- 声明为 final 的基本数据类型或 String 类型变量,并且在声明时进行初始化赋值。
- 初始值必须是一个在编译时就能确定的常量表达式,例如字面值常量或其他编译期常量的组合。
private final int valueOne = 1;
private static final int VALUE_TWO = 2;
valueOne 和 VALUE_TWO 均为编译期常量。使用 static 修饰的编译期常量全部使用大写字母命名,使用下划线连接。
当 final 修饰的变量是引用类型时,变量存储的地址值不能发生改变,对象内部可以改变。
public class Test {
public static void main(String[] args) {
final Student student = new Student("zhang", 18);
student.setName("Li");
student.setAge(20);
System.out.println(student.getName() + ":" +student.getAge());// Li:20
final int[] arr = {0, 1, 2, 3};
arr[0] = 11;
System.out.println(arr[0]);// 11
}
}
为什么字符串是不可变的?
// String.java
@Stable
private final byte[] value;
String 类中使用 final 修饰存储字符串的数组value,value指向的地址值不会改变。那存储的内容为什么不会改变呢?value 是 private 修饰的,并且 value 并没有提供 getter 和 setter 方法,所以字符串内容不会发生改变。
2.2 在运行时被初始化的常量
并不是使用 final 修饰的数据在编译时就可以知道它的值。
private static final int VALUE_THREE = new Random().nextInt(10);
VALUE_THREE 在运行时才会知道它的值。
3. 使用 final 修饰方法
3.1 将方法锁定
使用 final 修饰方法为了将方法锁定,以防止任何类修改方法含义,出于设计的考虑,想要确保在继承中方法行为保持不变。
3.2 效率(现已过时)
在 Java 的早期实现中,如果将一个方法指明为 final,就是同意编译器将针对该方法的所有调用都转为内嵌调用。现在 Java 的实现中,虚拟机可以探测到这些情况,并优化去掉一些效率反而降低的额外的内嵌调用,因此不再需要使用 final 方法来进行优化了。
3.3.final 与 private
类中所有的 private 方法都隐式地指定为是 final 的。由于无法取用 private 方法,所以也就无法覆盖它。可以对 private 方法添加 final 修饰词,但这并不能给该方法增加任何额外的意义。
4. 使用 final 修饰类
使用 final 修饰类时,该类不能进行任何改变,也不能被继承。
由于 final 类禁止继承,所以 final 类中所有的方法都隐式指定为是 final 的。在 final 类中可以给方法添加 final 修饰词,不会增添任何意义。