final关键字,可以定义在变量前,可以定义在方法前,也可以定义在类前。
final定义在变量前
首先,final定义的变量,是不允许修改的变量,所以,final变量的赋值,只能出现在两个地方,一个是定义时赋值,一个是构造函数赋值。成员变量可以分为primitive和reference,当primitive变量被定义成为final的时候,只允许在两个地方赋值,定义和构造函数,之后该变量就不能再发生改变。同时,如果在定义时赋值了,那么构造函数就不能再发生改变了。当reference变量被定义成为final的时候,与primitive相同的是,只允许在定义和构造函数赋值,与primitive不同的是,这里的赋值与改变的概念是reference的改变,也就是说,一旦你给予一个引用的时候(也就是说你给了这个引用一个具体的地址了,那么,这个引用就不能再指向其他地方了,形象一点的说就是,一旦final Object o = new Object()之后,就不能再o = new Object()了。)引用虽然不能改变,但是引用的对象的内容是可以改变的,怎么说呢,我定义了一个类FinalTest,其中它有一个成员变量finaltest,虽然不能在改变FinalTest的对象,但是,可以改变finaltest的内容。如果final与static同时使用,就定义了一个像C++里面的const关键字定义的一样,成为了一个常量。
final定义在方法前
final定义在方法前,是为了让此方法不能再扩展,也就是说子类可以继承它,但是不能在覆写它。需要考虑清楚的是,是否真的确定该方法真的就满足了你在该程序中的需要,因为一旦你让该方法变为final了,除非从代码级上改变然后重新编译整个项目,否则是不能改变的。
final定义在类前
java的API中就有被定义成为final的类,比如String,它是非常有必要的,当一个类被定义成为final后,它就无法被任何人继承(final的类的内容与普通类相同,成员可以是final也可以不是,不同的是,final的类的方法,不管写上或者不写,它都是final的,因为无法被继承),所以在定义前,还是要考虑整个程序或者说整个项目中,它是不是有必要被定义成为final。
定义final,要非常慎重,也许这个程序只是一个小东西,也不会再被升级成为2.0或者更高,那么定义为final也许不需要考虑太多,(其实很多小东西,反而很少用到final)如果要设计一个也许将来会扩展到8.0,9.0等等的版本的时候,就要考虑清楚了,它是否需要定义成为final。
对与java中的final变量,java编译器是进行了优化的。每个使用了final类型变量的地方都不会通过连接而进行访问。比如说A类中使用了B类中一个final的int数字var=1,这时候,java编译器会将1这个常数编译到A类的指令码或者常量池中。这样,每次A类用到var的时候,不会通过引用连接到B类中进行读取,而是直接使用自己保存在类文件中的副本。下面以一段代码来说明。
file A.java
public class A{
public static void main(String[] args){
System.out.println(B.var);
}
}
file B.java
public class B{
public static final int var = 1;
}
编译两个文件,得到输出1,这时候改变B.java文件中的var的值为2,这时候再去编译B.java再运行A的字节码文件,得到的输出还是1。如果把var前的关键字final去掉,或者重新编译A.java这时候才能得到输出1。