final 用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖、类不可被继承(不能再派生出新的子类)。
final 属性:被 final 修饰的变量不可变,由于不可变有两重含义,一是引用不可变,二是对象不可变。那么 Java final 到底指的是哪种含义呢?下面通过两个例子来进行说明。
public class Test {
public static void main(String[] arg) {
final StringBuffer s = new StringBuffer("Hello");
s.append("world");
System.out.println(s);
}
}
运行结果为:
Hello world
public class Test {
public static void main(String[] arg) {
final StringBuffer s = new StringBuffer("Hello");
s = new StringBuffer("Hello world");
}
)
运行结果:
编译期间错误
从以上两例子中可以看出,final 指的是引用的不可变性,即它只能指向初始时指向的那个对象,而不关心指向对象内容的变化。所以,被 final 修饰的变量必须被初始化。
一般可以通过以下几种方式对其进行初始化:
当一个方法声明为 final 时,该方法不允许任何子类重写这个方法,但子类仍然可以使用这个方法。另外还有一种被称为 inline(内联)的机制,当调用一个被声明为 final 的方法时,直接将方法主体插入到调用处,而不是进行方法调用(类似于 C++ 语言中的 inline),这样做能提高程序的效率。
用来表示这个参数在这个方法内部不允许被修改。
当一个类被声明为 final 时,此类不能被继承,所有方法都不能被重写。但这并不表示 final 类的成员变量也是不可改变的,要想做到 final 类的成员变量不可改变,必须给成员变量增加 final 修饰。注意,一个类不能既被声明为 abstract,又被声明为 final。
引申:为什么匿名内部类只能使用成员变量或者被 final 修饰的局部变量呢?
这是因为匿名内部类的生存期可能比一般的局部变量更久。
例如一个 Runable 的实现体,有可能在数秒之后才被调用,而它的外部方法体已经随着代码执行完毕而消亡了,之前定义在外部方法体内的变量随着方法区内存的回收也一起消亡了。而被 final 修饰的局部变量在匿名内部类中有一个引用的副本,由于它本身不可被修改引用,所以可以在开发期认为 final 局部变量和内部类的引用副本是同一个引用。