final
在
Java
中并不常用,然而它却为我们提供了诸如在
C
语言中定义常量的功能,不仅如此,
final
还可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能,这些特点使
final
在
Java
中拥有了一个不可或缺的地位,也是学习
Java
时必须要知道和掌握的关键字之一。
final 成员
当你在类中定义变量时,在其前面加上 final 关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。其初始化可以在两个地方,一是其定义处,也就是说在 final 变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值。下面这段代码演示了这一点:
此程序很简单的演示了
final
的常规用法。在这里使用在构造函数中进行初始化的方法,这使你有了一点灵活性。如
Bat
的两个重载构造函数所示,第一个缺省构造函数会为你提供默认的值,重载的那个构造函数会根据你所提供的值或类型为
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 用于类身上时,你就需要仔细考虑,因为一个 final 类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。对于 final 类中的成员,你可以定义其为 final ,也可以不是 final 。而对于方法,由于所属类为 final 的关系,自然也就成了 final 型的。你也可以明确的给 final 类中的方法加上一个 final ,但这显然没有意义。
下面的程序演示了 final 方法和 final 类的用法:
从程序中可以看出,
final
类与普通类的使用几乎没有差别,只是它失去了被继承的特性。
final
方法与非
final
方法的区别也很难从程序行看出,只是记住慎用!
final 成员
当你在类中定义变量时,在其前面加上 final 关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。其初始化可以在两个地方,一是其定义处,也就是说在 final 变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值。下面这段代码演示了这一点:
1
.
import
java.util.List;
2 . import java.util.ArrayList;
3 . import java.util.LinkedList;
4 . public class Bat ... {
5. final PI=3.14; //在定义时便给址值
6. final int i; //因为要在构造函数中进行初始化,所以此处便不可再给值
7. final List list; //此变量也与上面的一样
8. Bat()...{
9. i=100;
10. list=new LinkedList();
11. }
12. Bat(int ii,List l)...{
13. i=ii;
14. list=l;
15. }
16. public static void main(String[] args)...{
17. Bat b=new Bat();
18. b.list.add(new Bat());
19. //b.i=25;
20. //b.list=new ArrayList();
21. System.out.println("I="+b.i+" List Type:"+b.list.getClass());
22. b=new Bat(23,new ArrayList());
23. b.list.add(new Bat());
24. System.out.println("I="+b.i+" List Type:"+b.list.getClass());
25. }
26. }
2 . import java.util.ArrayList;
3 . import java.util.LinkedList;
4 . public class Bat ... {
5. final PI=3.14; //在定义时便给址值
6. final int i; //因为要在构造函数中进行初始化,所以此处便不可再给值
7. final List list; //此变量也与上面的一样
8. Bat()...{
9. i=100;
10. list=new LinkedList();
11. }
12. Bat(int ii,List l)...{
13. i=ii;
14. list=l;
15. }
16. public static void main(String[] args)...{
17. Bat b=new Bat();
18. b.list.add(new Bat());
19. //b.i=25;
20. //b.list=new ArrayList();
21. System.out.println("I="+b.i+" List Type:"+b.list.getClass());
22. b=new Bat(23,new ArrayList());
23. b.list.add(new Bat());
24. System.out.println("I="+b.i+" List Type:"+b.list.getClass());
25. }
26. }
I=100 List Type:class java.util.LinkedList
I=23 List Type:class java.util.ArrayList
还有一种用法是定义方法中的参数为 final ,对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传值的,也就是说你可以在方法中更改这个参数变量而不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量,当你在方法中不需要改变作为参数的对象变量时,明确使用 final 进行声明,会防止你无意的修改而影响到调用方法。
另外方法中的内部类在用到方法中的参变量时,此参变也必须声明为 final 才可使用,如下代码所示:
1
.
public
class
INClass
...
{
2. void innerClass(final String str)...{
3. class IClass...{
4. IClass()...{
5. System.out.println(str);
6. }
7. }
8. IClass ic=new IClass();
9. }
10. public static void main(String[] args)...{
11. INClass inc=new INClass();
12. inc.innerClass("Hello");
13. }
14. }
2. void innerClass(final String str)...{
3. class IClass...{
4. IClass()...{
5. System.out.println(str);
6. }
7. }
8. IClass ic=new IClass();
9. }
10. public static void main(String[] args)...{
11. INClass inc=new INClass();
12. inc.innerClass("Hello");
13. }
14. }
final方法
将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。
final
类
将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。
当你将 final 用于类身上时,你就需要仔细考虑,因为一个 final 类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。对于 final 类中的成员,你可以定义其为 final ,也可以不是 final 。而对于方法,由于所属类为 final 的关系,自然也就成了 final 型的。你也可以明确的给 final 类中的方法加上一个 final ,但这显然没有意义。
下面的程序演示了 final 方法和 final 类的用法:
1
.
final
class
final
...
{
2. final String str="final Data";
3. public String str1="non final data";
4. final public void print()...{
5. System.out.println("final method.");
6. }
7. public void what()...{
8. System.out.println(str+" "+str1);
9. }
10. }
11 . public class FinalDemo ... { //extends final 无法继承
12. public static void main(String[] args)...{
13. final f=new final();
14. f.what();
15. f.print();
16. }
17. }
2. final String str="final Data";
3. public String str1="non final data";
4. final public void print()...{
5. System.out.println("final method.");
6. }
7. public void what()...{
8. System.out.println(str+" "+str1);
9. }
10. }
11 . public class FinalDemo ... { //extends final 无法继承
12. public static void main(String[] args)...{
13. final f=new final();
14. f.what();
15. f.print();
16. }
17. }