final可以修饰域、方法、类,有不可改变之意,下面会依次讲解。
一、域
final修饰域分两种情况:
- 1.final修饰基本类型,则基本类型的数值不可改变。
- 2.final修饰对象引用,则对象引用不可改变;一旦引用已经初始化完成指向一个对象,就不能让这个引用指向另一个对象了;但是对象本身却是可以被改变的。
读者可以结合下面的例子更直观的理解上面的概念:
/**
* @Description 木头
* @Author .Mark
* @Date 2019年2月22日
*/
class Wood {
String kind;
Wood(String kind) {
this.kind = kind;
}
@Override
public String toString() {
return kind;
}
}
/**
* @Description 木制椅子
* @Author .Mark
* @Date 2019年2月22日
*/
public class WoodenChair {
// 靠背的数量
private final int numOfBackrest = 1;
// 椅子腿儿的数量
public final static int NUM_OF_LEG = 4;
// 材质
private final Wood wood = new Wood("花梨木");
public static void main(String[] args) {
WoodenChair woodenChair = new WoodenChair();
// final修饰的基本类型,数值不可以改变
// woodenChair.numOfBackrest = 2;
// final修饰的对象,引用不可以更改
// woodenChair.wood = new Wood("紫檀木");
System.out.print("最初我想用" + woodenChair.wood + "做一把椅子,");
// finnal修饰的对象,对象本身是可以被修改的
woodenChair.wood.kind = "紫檀木";
System.out.println("但后来还是觉得用" + woodenChair.wood + "更好。");
}
}
// output: 最初我想用花梨木做一把椅子,但后来还是觉得用紫檀木更好。
final对基本类型的修饰,通常使用例子中对“椅子腿儿数量”的声明方式。public使得其他人可以直接访问这个域;static使得所有对象共享一份存储空间;final使得这个域的值恒定。
二、空白final
我是第一次接触空白final的用法,并没有经验但又觉得这个概念有用,所以就摘了《Java编程思想》的讲解出来解释它。
Java允许生成“空白final”,所谓空白final是指被声明为final但又未给定初值的域。无论什么情况,编译器都保证空白final在使用前必须被初始化。但是,空白final在关键字final的使用上提供了更大的灵活性,为此,一个类中的final域就可以做到根据对象而有所不同,却又保持其恒定不变的特性。下面即为一例:
class Poppet {
private int i;
Poppet(int ii) {
i = ii;
}
}
public class BlankFinal {
// Initiallized final
private final int i = 0;
// Blank final
private final int j;
// Blank final reference
private final Poppet p;
// Blank finals MUST be initialized in the constuctor;
public BlankFinal() {
// Initialize blank final
j = 1;
// Initialize blank final reference
p = new Poppet(1);
}
public BlankFinal(int x) {
// Initiallize blank final
j = x;
// Initiallize blank final reference
p = new Poppet(x);
}
public static void main(String[] args) {
new BlankFinal();
new BlankFinal(47);
}
}
必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总被初始化的原因所在。
三、方法
final修饰的方法,子类不能对它进行重写。
/**
* @Description 树
* @Author .Mark
* @Date 2019年2月23日
*/
class Tree {
// 树高
private double height;
public final void grow(double increment) {
height += increment;
}
}
/**
* @Description 白杨
* @Author .Mark
* @Date 2019年2月23日
*/
public class Poplar extends Tree {
// 子类不能重写父类的final方法
// public final void grow(double increment) { }
public static void main(String[] args) {
Poplar poplar = new Poplar();
// 但是子类可以正常调用父类的final方法
poplar.grow(1.0);
}
}
private方法实际上已经被隐式的声明为final的了,你可以为private方法加上final修饰符,但实际上这个final起不到任何作用。如下示例:
/**
* @Description 树
* @Author .Mark
* @Date 2019年2月23日
*/
class Tree {
// 树高
private double height;
private final void grow(double increment) {
height += increment;
}
}
/**
* @Description 白杨
* @Author .Mark
* @Date 2019年2月23日
*/
public class Poplar extends Tree {
public final void grow(double increment) { }
}
这里容易产生个错觉,即子类可以重写父类的private方法。但实际上因为子类不能继承父类private的属性和方法,所以这里也就谈不上什么重写,而只是重新写了一个和父类一样的方法,这个方法和父类的那个方法没有任何关系。
四、类
final修饰的类,不能被继承。