在 Java 中,有三种情况可能使用到 final:数据、方法和类。
1. final 数据
对于基本类型,final 使数值恒定不变;对于对象引用,final 使其引用不变,但是引用指向的对象本身可以被修改,数组也是对象。
public class finalData {
private static final int VAL_1 = 1;
private final Value value_1 = new Value(2);
private final int a[] = {1, 2, 3, 4};
public static void main(String[] args) {
finalData finalData = new finalData();
// finalData.VAL_1 = 2; // error:Cannot assign a value to final variable 'VAL_1'
// finalData.value_1 = new Value(3); // error:Cannot assign a value to final variable 'value_1'
finalData.value_1.i++;
// finalData.a = new int[3]; //error:Cannot assign a value to final variable 'a'
for (int i = 0; i < finalData.a.length; i++) {
finalData.a[i]++;
}
}
}
class Value {
int i;
public Value(int i) {
this.i = i;
}
}
可以看到,虽然引用 value_1 不能改变,但是其成员 i 是可以改变的,数组 a 同理。
空白 final
空白 final 是指被声明为 final 但又未给定初值的域。但是无论什么情况,编译器都会确保空白 final 在使用前被初始化,否则会提示未初始化变量。
final 参数
将参数指明为 final 时,意味着无法在方法中更改参数引用所指向的对象。
public class FinalArguments {
void without(Gizmo g){
g = new Gizmo();
g.spin();
}
void with(final Gizmo g){
// g = new Gizmo(); // Error,g 被定义为 final
}
void g(final int i){
// i++; // Error,i 被定义为 final
}
int f(final int i){
return i+1;
}
public static void main(String[] args) {
FinalArguments fa = new FinalArguments();
Gizmo gizmo = new Gizmo();
fa.with(gizmo);
fa.without(gizmo);
}
}
class Gizmo{
public void spin(){}
}
2. final 方法
使用 final 方法可以把方法锁定,防止任何继承类修改它的定义。
类中所有的 private 方法都隐式地指定为 final 的,继承类无法取到 private 方法,当然也无法覆盖它,所以为 private 方法添加 final 修饰词毫无意义。
class WithFinals {
private final void f(){
System.out.println("WithFinals.f()");
}
private void g(){
System.out.println("WithFinals.g()");
}
}
class OverridingPrivate extends WithFinals{
// 虽然此时 OverridingPrivate 继承了 WithFinals 类,但是这并不是重写的父类方法,只是名字相同而已
private final void f(){
System.out.println("OverridingPrivate.f()");
}
private void g(){
System.out.println("OverridingPrivate.g()");
}
public static void main(String[] args) {
OverridingPrivate op = new OverridingPrivate();
op.f();
op.g();
WithFinals wf = op;
// wf.f(); 子类对象无法调用父类对象的私有方法
// wf.g(); 子类对象无法调用父类对象的私有方法
}
}
3. final 类
当使用 final 修饰类时,表明该类无法被继承。
由于 final 类禁止继承,所以 final 类中所有方法隐式指定为 final 的,因为无法覆盖它们。
final class Dinosaur {
int i = 1;
}
// class Further extends Dinosaur{} // Error:Cannot inherit from final 'Dinosaur'
总结
被 final 修饰的数据/方法/类无法被改变
- final 修饰基本类型时,该数据被初始化一次后无法改变,当 final 修饰引用类型时,该引用不可变,但是引用指向的对象本身可变。
- final 修饰方法时,该方法无法被重写
- final 修饰类时,该类无法被继承