Java中final几种常用用法及final关键字的作用说明


Java中的final共有三种用法:

final成员变量
当你在类中定义变量时,在其前面加上final关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本的类型来说是其值不可变,而对于对象变量来说其引用不可再变,但引用变量所指向的对象中的内容还是可以改变的

其初始化可以在三个地方:
一是其定义处,也就是说在final变量定义时直接给其赋值;
二是在构造方法中,而且在java1.1以前,只能时在定义的时候给赋值;
三是在初始化代码块中 {} 或者 static{}
下面这段代码演示了这一点:
public class FinalUseTest {

final double PI = 3.14; // 在定义时便给址值
final int i; // 因为要在构造函数中进行初始化,所以此处便不可再给值
final List<FinalUseTest> list; // 此变量也与上面的一样

FinalUseTest() {
i = 100;
list = new LinkedList<>();
}

FinalUseTest(int ii, List<FinalUseTest> l) {
i = ii;
list = l;
}

public static void main(String[] args) {

FinalUseTest b = new FinalUseTest();
b.list.add(new FinalUseTest());//引用不可变,但引用指向的内容是可以变的
// b.i=25;// syntax error i是不可变的
// b.list=new ArrayList();// 错误,对象引用是不可变的
System.out.println("I=" + b.i + " List Type:" + b.list.getClass());
b = new FinalUseTest(23, new ArrayList<FinalUseTest>());
b.list.add(new FinalUseTest());
System.out.println("I=" + b.i + " List Type:" + b.list.getClass());
}
}

再例如,对于如下语句:

final static StringBuffer a=new StringBuffer("dachun");
  执行如下语句将报告编译期错误:
a=new StringBuffer("");
  但是,执行如下语句则可以通过编译:
a.append("zuishuai");

有人在定义方法的参数时,可能想采用如下形式来阻止方法内部修改传进来的参数对象:
public void method(final StringBuffer param){
}
实际上,这是办不到的,在该方法内部仍然可以增加如下代码来修改参数对象,其它对象亦如此:
param.append("a");

此程序很简单的演示了final的常规用法。在这里使用在构造函数中进行初始化的方法,这使你有了一点灵活性。如FinalUseTest的两个重载构造函数所示,第一个缺省构造函数会为你提供默认的值,重载的那个构造函数会根据你所提供的值或类型为final变量初始化。然而有时你并不需要这种灵活性,你只需要在定义时便给定其值并永不变化,这时就不要再用这种方法。在main方法中有两行语句注释掉了,如果你去掉注释,程序便无法通过编译,这便是说,不论是i的值或是list的类型,一旦初始化,确实无法再更改。然而b可以通过重新初始化来指定i的值或 list的类型,输出结果中显示了这一点:
I=100 List Type:class java.util.LinkedList
I=23 List Type:class java.util.ArrayList

还有一种用法是定义方法中的参数为final,对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传值的,也就是说你可以在方法中更改这个参数变量而不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量,当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法。


final方法
将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。

另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。

类中所有的private方法从某种意义上讲都是属于final的,因为他们在其它地方没法覆盖,你可以在一个private方法前加final修饰符,但没什么意义。

final类
当你将final用于类身上时,你就需要自习考虑,因为一个final时无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。

对于final类中的成员变量,你可以定义其为final,也可以不是final;而对于方法,由于所属类为final的关系,自然也就成了final型的。你也可以明确的给final类中的方法加上一个final,但显然没有意义。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM