使用final的两个原因:设计和效率,这两个原因相差很多,导致final会被误用。
1. 在数据上使用final
向编译器告知一块数据是恒定不变的。
- - - 两种情况:
一个永不改变的编译时常量;
一个在运行时被初始化的值,而你不希望它被改变。
对于编译期常量这种情况,编译器可以将该常量代入任何可能用到的计算公式中,在编译时执行计算式,减轻了运行时的负担。
Java中,这类常量必须是基本数据类型,并且以关键字final表示,这个常量一定要进行初始化。
对对象引用运用final时,引用指向的对象无法改变,但是对象自身是可以被修改的,(同样适用数组,它也是对象)
注:一个既是static又是final的域只占一段不能改变的存储空间。
对象的情况:
public class Test2 {
public int a = 0;
public static void main(String[] args) {
final Test2 test1 = new Test2();
// test1的引用不可以指向test2
Test2 test2 = new Test2();
// test1 = test2; 编译时错误
// 对象自身可以被改变
System.out.println(test1.a); // 0
test1.a = 2;
System.out.println(test1.a); // 2
}
}
数组的情况:
public class Test2 {
public static void main(String[] args) {
final int[] arr_int = { 1, 2, 3 };
// arr_int数组元素可以改变
// 123
printArray(arr_int);
arr_int[0] = 2;
// 223
printArray(arr_int);
// arr_int的引用不可以指向arr_int_2
int[] arr_int_2 = { 3, 2, 3 };
// arr_int = arr_int_2;
}
// 打印数组
public static void printArray(int[] arr) {
for (int a : arr) {
System.out.print(a);
}
System.out.println();
}
}
注:
不能因为某个数据是final的就认为在编译时可以指导它的值,可以在运行时进行赋值。
Random ran = new Random(47);
final int a = ran.nextInt(20);
// 18
System.out.println(a);
2. 在方法参数上使用final
Java允许在参数列表中以声明的方式将参数指明为final。这说明无法在方法内部更改引用指向的对象
void test(final Test2 test) {
// 不能更改引用指向
// test = new Test2();
}
3. 在方法上使用final
第一个原因:
把方法锁定,以防任何继承类来修改它。
第二个原因:
效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。
注:
类中所有的private方法都隐式地指定为final的。
这一问题可能会导致你混淆:子类可以覆盖父类的方法。
下面的代码子类Child和父类Father有相同的方法:say()
“覆盖”只有在某方法是基类的接口的一部分时才会出现。如果某方法是private的,那它就不是基类的接口的一部分,它仅是一些隐藏于类中的程序代码。子类根本访问不到父类的say方法,所以只是子类和父类方法名相同罢了,子类只认为是自己特有的方法,而父类没有,子类中say方法就是一个新的方法,并没有覆盖父类的say方法。
public class Test2 {
public static void main(String[] args) {
Child child = new Child();
child.say();
Father fchild = child;
// 不能调用该方法
// fchild.say();
}
}
class Father {
private final void say() {
System.out.println("Father");
}
}
class Child extends Father {
public final void say() {
System.out.println("Child");
}
}
4. 在类上使用final
final用在类上表示该类不允许被继承。
由于final类是禁止继承的,所以类中所有方法都隐式指定为final的。