《Java编程思想》
final是Java的一个非访问控制修饰符(non-access modifier),可以用于修饰变量、方法和类,有着“不可变”的作用。下面我们简单看一下final有哪些用法。
1 final变量
当一个变量被final修饰时,它分为两种情况:
当这个变量是一个基本数据类型时,这时就意味着该变量是可读的、不可更改的常量(constant),对于常量,有两个方面的应用:
(1)编译时常数,它永远不会改变,对于编译期的常数,编译器可将常数值“封装”到需要的计算过程里。也就是说,计算可在编译期间提前执行,从而节省运行时的一些开销;
(2)在运行期初始化的一个值,我们不希望它发生变化;
而当这个变量是一个对象的引用时,它表示的则是引用只能被赋值一次(引用不可变,但对象本身可变)。
final int MY_CONSTANT_INT = 1;//编译时常数
// MY_CONSTANT_INT = 2; //编译错误
final int MY_RUNTIME_CONSTANT_INT = (int) (Math.random() * 10);//运行时常数
// MY_RUNTIME_CONSTANT_INT = 3;//编译错误
final List<String> MY_CONSTANT_LIST = new ArrayList<>();
// MY_CONSTANT_LIST = new ArrayList<>();//编译错误
MY_CONSTANT_LIST.add("aa");
2 final方法
当一个方法被声明为final时,意味着该方法不能被子类覆盖重写(overridden)。
class BaseClazz{
public final void method() {
}
}
class ChildClazz extends BaseClazz{
//编辑错误
// public final void method() {
//
// }
}
同时,在执行上,final方法比final方法有着更高的效率,编译器会把对final方法的调用转换为内联(inline)方法调用,即忽略为执行方法调用机制(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)而采取的常规代码嵌入方法。相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销。当然,若方法体积太大,那么程序也会变得雍肿,可能感受不到嵌入代码所带来的任何性能提升。因为任何提升都被花在方法内部的时间抵消了。 Java 编译器能自动侦测这些情况,并颇为“明智”地决定是否嵌入一个 final 方法。
另外,类的 private 方法都自动成为 final方法。
3 final类
如果一个类被final修饰的话,则表明这个类是不可继承的,我们常用的String就是一个final修饰的类:
final class BaseClazz{
public final void method() {
}
}
//错误
//class ChildClazz extends BaseClazz{
//
//}
另外,final类的方法都自动成为 final方法。
4 空白final
空白final是指,已经声明但并未进行初始化的final变量,但编译器会保证该变量在实际使用前得到正确的初始化。
final int BLANK_FINAL_INT;//空白final
BLANK_FINAL_INT = 2;
但如果空白final作为成员变量出现,那么如何保证它的初始化呢,两种方式:
public class BlankFinalTest {
final int BLANK_FINAL_MEM_INT1;
//代码块初始化
{
BLANK_FINAL_MEM_INT1 = 1;
}
final int BLANK_FINAL_MEM_INT2;
//构造函数初始化
public BlankFinalTest(int i) {
BLANK_FINAL_MEM_INT2 = i;
}
}
使用空白final创建一个不可变(内容不可变)的对象:
class ImmutableClazz{
public final int CONSTAIN_II;
public ImmutableClazz(int i) {
CONSTAIN_II = i;
}
}
//...
public static void main(String[] args) {
ImmutableClazz immutableClazz = new ImmutableClazz(11);
// immutableClazz.CONSTAIN_II = 2;//编译错误
}
5 final和static的区别
final和static修饰符常成对出现,用于声明常量,但final和static有着什么区别呢?
static成员变量表示只保存一份副本,并且所有对象共享该变量;而final的作用是用来保证变量不可变。
final class BaseClazz{
public final double FINAL_DD = Math.random();
public static double STATIC_DD = Math.random();
public final void method() {
}
public static void main(String[] args) {
BaseClazz b1 = new BaseClazz();
BaseClazz b2 = new BaseClazz();
System.out.println(b1.FINAL_DD);
System.out.println(b2.FINAL_DD);
System.out.println(b1.STATIC_DD);
System.out.println(b2.STATIC_DD);
}
}
输出:
0.17103733059790327
0.237554219342485
0.7814031755793921
0.7814031755793921