final是java面试中最常被问到的问题,不管是面试还是笔试都经常会出现此类问题。还是经常会出现问题,就仔细的讲解一下final。
Java的关键字final的含义存在着细微的区别,但通常它指的是“这是无法改变的”不想做改变可能出于两种理由:设计或者效率。可能使用到final的三种情况:变量、方法和类。
(一)final 变量
final关键字声明的变量被认为是常量,任何在程序中试图改变常量值的操作,都会导致编译时错误。对于基本类型,final使数值恒定不变,而用于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象,然而对象其自身却是可以被修改的。下面的示例示范了final域的情况。
import java.util.Random;
class Value {
int i;
public Value(int i) {
this.i = 1;
}
}
public class FinalData {
private static Random rand = new Random(47);
private String id;
public FinalData(String id) {
this.id = id;
} // Can be compile-time constants
private final int valueOne = 9;
private static final int VALUE_TWO = 99; // Typical public constant
public static final int VALUE_THREE = 39; // cannot be compile-time
// constants
private final int i4 = rand.nextInt(20);
static final int INT_5 = rand.nextInt(20);
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
private static final Value VAL_3 = new Value(33);
// Arrays
private final int[] a = { 1, 2, 3, 4, 5, 6 };
public String toString() {
return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;
}
public static void main(String[] args) {
FinalData fd1 = new FinalData("fd1");
// !fd1.valueOne++ ;
// Error:can't change value
fd1.v2.i++;// object isn't constant!
fd1.v1 = new Value(9);
// ok ---not final
for (int i = 0; i < fd1.a.length; i++) {
fd1.a[i]++; // object isn't constant
// ! fd1.v2 = new value(0); // Error can't
// ! fd1.VAL_3 = new Value(1); //change reference
// ! fd1.a = new int[3];
}
System.out.println(fd1);
System.out.println("Creating new FianlData");
FinalData fd2 = new FinalData("fd2");
System.out.println(fd1);
System.out.println(fd2);
}
}
运行结果:
fd1: i4 = 15, INT_5 = 18
Creating new FianlData
fd1: i4 = 15, INT_5 = 18
fd2: i4 = 13, INT_5 = 18
由于valueOne和VAL_TWO 都是带有编译时数值的final基本类型,所以他们两者均可以用做编译期常量,并没有重大区别。VAL_THREE是一种更加典型的对常量进行定义的方式:定义为public则可以被用于包之外,定义为static则强调只有一份,定义为final则说明他是一个常量。在fd1 和fd2中,i4的值是唯一的,但INT_5的值是不可以通过创建第二个FinalData对象而加以改变的,这是因为它是static的,在装载时已经被初始化,而不是每次创建新对象时都初始化。
(1)final变量不需要在声明时初始化,程序也可以在声明之后的其他地方初始化final变量。不过这样的初始化必须只执行一次,并且在使用final之前必须初始化。声明时未初始化的final变量叫空缺final变量。
(2) Java允许在参数列表中以声明的方式将参数指明为final。这意味着你无法在方法中更改参数引用所指向的对象。
class Gizmo {
public void spin() {
}
}
public class FinalArgument {
void with(final Gizmo g) {
// ! g = new Gizmo(); //Illeagl — g is final
}
void without(Gizmo g) {
g = new Gizmo(); // ok g not final
g.spin();
}
// void f(final int i){i++;} //can't change
int g(final int i) {
return i + 1;
}
public static void main(String[] args) {
FinalArgument bf = new FinalArgument();
bf.without(null);
bf.with(null);
}
}
(二) final方法
使用final方法是把方法锁定,以防任何继承类修改他的含义,确保在继承中使方法行为保持不变,并不会被覆盖。final方法不可以在子类中被重写。
类中所有的private方法都是隐式地指定为是final的。
(三) final类
当将某个类的整体定义为final时,就表明该类不能被继承。该类不需要做任何变动。