Java关键字之final详解

在我们编写Java程序时总会根据需求将变量、方法、类设置成static(静态)或final(最终),熟练掌握final用法是必须的,现在我们就来详细了解final关键字!

一、final概述

概念:由字面可以了解,final有最终态,无法改变的意思。

使用目的:为了阻止改变与提高效率。

高效原因:Java内嵌机制,final方法会在编译的过程中利用内嵌机制进行inline优化。

inline优化是指:在编译的时候直接调用方法代码替换,也就是内嵌,而不是在运行时调用方法。

inline需要在编译的时候就知道最后要用哪个方法。

显然,非final是不行的。
非final方法可能在子类中被重写,由于可能出现多态的情况,编译器在编译阶段
并不能确定将来调用方法的对象的真正类型,也就无法确定到底调用哪个方法。)

修饰对象:

1、非抽象类,由于被final修饰的类是不能被继承的,而抽象类必须被继承才有意义。

2、非抽象方法,由于被final修饰的方法是不能被重写的,而抽象方法必须被重写才有意义。

3、变量或常量。

注意:

1、final不能修饰构造方法。

2、父类的private方法是不能被子类重写的,因为private方法默认是final的。

二、具体用法

1、修饰类

final类不能被继承,所有其成员与方法自然没有机会被覆盖,默认是final的。所以在将类设计成final类的时候,一定要特别慎重考虑,确定这个类不需要有子类,类实现不能被改变,类不能被扩展的时候才能用final修饰。

注:Java中String类就是一个final类。

2、修饰方法

如果一个类不允许其子类覆盖某个方法,则可以把这个方法用final修饰。

这样做的目的可在《Java编程思想》中查到:

“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。”

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Test1 {          
  2. public static void main(String[] args) {   
  3.     // TODO 自动生成方法存根   
  4. }   
  5. public void f1() {   
  6.     System.out.println("f1");   
  7. }   
  8. //无法被子类覆盖的方法   
  9. public final void f2() {   
  10.     System.out.println("f2");   
  11. }   
  12. public void f3() {   
  13.     System.out.println("f3");   
  14. }   
  15. private void f4() {   
  16.     System.out.println("f4");   
  17. }   
  18. }   
  19. public class Test2 extends Test1 {   
  20.       
  21. public void f1(){       
  22.     System.out.println("Test1父类方法f1被覆盖!");   
  23. }   
  24. public static void main(String[] args) {   
  25.     Test2 t=new Test2();   
  26.     t.f1();      
  27.     t.f2(); //调用从父类继承过来的final方法   
  28.     t.f3(); //调用从父类继承过来的方法   
  29.     //t.f4(); //调用失败,无法从父类继承获得   
  30. }   
  31. }  



 

 

 

3、修饰变量(重点)

1、final修饰基本数据类型变量,则其数值一旦被初始化就不能被更改。

2、final修饰引用变量(如ObjectName obj = new ObjectName();中obj就是一个引用变量,指向堆内存中对象空间的首地址),则其初始化后就不能修改引用指向另一个对象。

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. public class Test2 {          
  2.         private final String S = "final实例变量S";   
  3.         private final int A = 100;   
  4.         public final int B = 90;   
  5.   
  6.         public static final int C = 80;   
  7.         private static final int D = 70;   
  8.   
  9.         public final int E; //final空白,必须在初始化对象的时候赋初值   
  10.   
  11.         public Test3(int x) {   
  12.                 E = x;   
  13.         }   
  14.   
  15.         /**  
  16.          * @param args  
  17.          */   
  18.         public static void main(String[] args) {   
  19.                 Test3 t = new Test3(2);   
  20.                 //t.A=101;    //出错,final变量的值一旦给定就无法改变   
  21.                 //t.B=91; //出错,final变量的值一旦给定就无法改变   
  22.                 //t.C=81; //出错,final变量的值一旦给定就无法改变   
  23.                 //t.D=71; //出错,final变量的值一旦给定就无法改变   
  24.   
  25.                 System.out.println(t.A);   
  26.                 System.out.println(t.B);   
  27.                 System.out.println(t.C); //不推荐用对象方式访问静态字段   
  28.                 System.out.println(t.D); //不推荐用对象方式访问静态字段   
  29.                 System.out.println(Test3.C);   
  30.                 System.out.println(Test3.D);   
  31.                 //System.out.println(Test3.E); //出错,因为E为final空白,依据不同对象值有所不同.   
  32.                 System.out.println(t.E);   
  33.   
  34.                 Test3 t1 = new Test3(3);   
  35.                 System.out.println(t1.E); //final空白变量E依据对象的不同而不同   
  36.         }   
  37.   
  38.         private void test() {   
  39.                 System.out.println(new Test3(1).A);   
  40.                 System.out.println(Test3.C);   
  41.                 System.out.println(Test3.D);   
  42.         }   
  43.   
  44.         public void test2() {   
  45.                 final int a;     //final空白,在需要的时候才赋值   
  46.                 final int b = 4;    //局部常量--final用于局部变量的情形   
  47.                 final int c;    //final空白,一直没有给赋值.      
  48.                 a = 3;   
  49.                 //a=4;    出错,已经给赋过值了.   
  50.                 //b=2; 出错,已经给赋过值了.   
  51.         }   
  52. }  

四、修饰参数

 

当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
    1. public class Test3 {          
    2.         public static void main(String[] args) {   
    3.                 new Test4().f1(2);   
    4.         }   
    5.   
    6.         public void f1(final int i) {   
    7.                 //i++;    //i是final类型的,值不允许改变的.   
    8.                 System.out.print(i);   
    9.         }   
    10. }  
posted @ 2016-12-05 14:48  天涯海角路  阅读(315)  评论(0)    收藏  举报