Java 中的 final 关键字
关键字 final 一般的含义是指“不能被被改变的”,但是根据使用情况的不同,它的具体含义有所不同。final 修饰的东西无非就三样:数据、方法和类。
1. final 数据
final 修饰可以修饰的数据有两种:基本类型数据和对象引用数据。
-
当 final 修饰基本类型数据时,它告诉编译器这块数据时恒定不变的常量。常量必须在定义是进行赋值。更进一步的,使用 static 和 final 同时修饰的基本类型属性只能占用一块固定的存储空间,即静态常量。
-
当 final 修饰对象引用时,它表示了该引用的恒定不变。其含义是该引用一旦被初始化指向了某个对象,就不能再修改为指向其他对象,但是对象本身的内容时可以修改的。
注意:
-
final 修饰的数据在定义时是可以不立刻进行初始化的,但必须要保证空白 final 属性在使用前被初始化。
-
方法参数作为数据,也是可以被 final 修饰的,这意味着在被传入的参数表示的基本类型变量或者指向的对象在方法中不能被改变。
2. final 方法
final 修饰方法的作用作用是使方法不可被重写。这是针对继承特性的,如此方法的行为不会因继承发生任何改变。所有的 private 方法都隐式地指定为了 final 方法,给 private 方法再添加 final 关键字是多余的。但是要注意单是用 final 修饰地方法并不是 private 的,可以被继承,只有使用权,没有修改权。
早期的 Java 版本中将方法定义为 final 有另一个作用:将方法编译为内嵌调用。普通的方法调用机制是将参数压栈,跳转至方法代码处执行,然后跳回并清理栈中的参数,最终处理返回值的过程。内嵌调用是直接用方法体内的代码代替方法的调用,相当于直接把方法体中的代码直接复制到方法调用处。这样做确实省去了压栈和跳转过程的,但是如果方法体本身代码量很大,这种方式带来的性能提升很容易被在方法体中的消耗所抵消了。在后来的 Java 版本中,虚拟机可以探测到这些情况,并去掉这些效率反而降低的内嵌调用方法。
所以,性能问题是编译器和虚拟机考虑的事,对于 final 在方法上的使用,我们只需要考虑是否要禁止方法被重写这一件事就行了。
3. final 类
使用 final 修饰类的作用同样是针对继承来说的,即是说 final 修饰的类不能被继承。既然 final 类本身都不能被继承,那么类中的所有成员自然也无法被继承了,重写也就无从谈起。