讨论final使用的三种情况:数据,方法和类
final数据
1,一个永不改变的编译时常量
2,一个在运行时被初始化的值,而你不希望它被改变
例
import java.util.*;
class Value{
int i;
public Value(int i){this.i=i;}
}
public class FinalData {
private static Random rand =new Random(47);
private String id;
public FinalData (String id){
this.id=id;
}
private final int valueOne=9;
private static final int VALUE_TWO=99;
public static final int VALUE_THREE=39;
private final int i4=rand.nextInt(20);
static final int INT_5=rand.nextInt(20);
private Value v1=new Value(1);
private final Value v2=new Value(22);
private static final Value VAL_3=new Value(33);
private final int[] a={1,2,3,4,5,6};
public String toString(){
return id+": "+"i4="+i4+",INT_5:"+INT_5;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
FinalData fd1=new FinalData("fd1");
fd1.v2.i++;
fd1.v1=new Value(9);
for(int i=0;i<fd1.a.length;i++)
fd1.a[i]++;
System.out.println(fd1);
System.out.println("Create new FinalData");
FinalData fd2=new FinalData("fd2");
System.out.println(fd1);
System.out.println(fd2);
}
}
结果
fd1: i4=15,INT_518
Create new FinalData
fd1: i4=15,INT_518
fd2: i4=13,INT_518
解析:
i4仅仅是final类型,分别在两个对象中各开辟一块空间
static final 仅使用一段不能改变的空间,所以INT_5值不变
空白final
指被声明为final但又未给定初始值的域,编译器保证空白final使用前必须被初始化
final类型参数
无法在方法中更改参数引用所指向的对象
final方法
类中所有private方法都隐式地制定为是final的,一个类继承基类的private方法(final),可以覆盖private final方法。但如果在导出类中以相同的名称生成一个public,protected或包访问权限方法的话,此时并没有覆盖该方法,仅是生成了一个新的方法。
将方法声明为final那有两个原因,第一就是说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。第二就是允许编译器将所有对此方法的调用转化为inline调用的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。
例
import javax.swing.text.GapContent;
import org.omg.CORBA.PRIVATE_MEMBER;
class WithFinals{
private final void f(){
System.out.println("WithFinals.f()");
}
private void g(){
System.out.println("WithFinals.g()");
}
}
class OverridingPrivate extends WithFinals{
private final void f(){
System.out.println("OverridingPrivate.f()");
}
private void g(){
System.out.println("OverridingPrivate.g()");
}
}
class OverridingPrivate2 extends OverridingPrivate{
public final void f(){
System.out.println("OverridingPrivate2.f()");
}
public void g(){
System.out.println("OverridingPrivate2.g()");
}
}
public class FinalOverridingIilusion {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
OverridingPrivate2 op2=new OverridingPrivate2();
op2.f();
op2.g();
}
}
结果
OverridingPrivate2.f()
OverridingPrivate2.g()
如果将 WithFinals的g()方法前private改为final,则后面的覆盖就会报错,因为单单的final方法不允许覆盖,可以直接调用
final类
当某个类整体定义为final,表明了不能继承该类。该类的设计永不需要做任何改动 ,或出于安全考虑,不希望它有子类
final类的域可以选择是什么类型,是或不是fianl,默认指定final,无法覆盖它们