在Java中,final可以修饰类,方法,属性。

一 final数据

final关键字修饰变量,用来向编译期告知这块数据恒定不变:

在Java中这类常量必须是基本类型,编译期可以将该常量代入到可能用到它的表达式中,也就是说,可以在编译期执行计算;

[java] view plain copy

  1. private final int valueOne = 1;  
  2. public static final int VALUE_TWO = 2;  

 

 

 2.一个运行期时被初始化的值,一旦初始化完成,将不再改变。

[java] view plain copy

  1. private final  Random rand = new Random(100);  
  2. private final int valueThree =rand.nextInt(50);  

 

当final修饰的是对象引用时,要特别注意一定:该引用不能改变,但是该引用指向的对象却可以修改。这一限制同样适用于数组,它也是对象。

[java] view plain copy

    1. //无法将r再指向另外一个新的对象,array也不能指向新的数组
    2. private final Refe r = new Refe(23);  
    3. private int[] array = {1,2,3,4,5,6};  
    4.   
    5. public void changeFinalRefeObject() {  
    6. //编译无法通过,不允许修改r
    7. //r = new Refe(22);
    8.       
    9. //但是修改r所指向的对象却是可以的
    10. 22;  
    11.       
    12. //编译无法通过,不允许修改array
    13. //array = new int[6];
    14.       
    15. //修改数组的内容却是可以的
    16. 0] = 10;  
    17. }

     

    空白final(没在定义处给出值),需要注意一些,但是稍加思考,都是符合逻辑的:

    1.static final:static final是类变量,且只能初始化一次,所以这类变量这能在静态语句块中初始化;

    [java] view plain copy

    1. public static final int VALUE_ONE;  
    2. //只能在静态语句块中初始化
    3. static {  
    4. 1;  
    5. }

     

    2.非static final:非静态语句块先于构造方法执行,所以可以在非静态语句块中对final变量赋值;

    [java] view plain copy

    1. private final int valueOne;  
    2. //在执行构造方法前,先执行非静态语句块
    3. {  
    4. 1;  
    5. }

     

    3.如果在构造方法中对final变量赋值的话,所有的构造方法都必须有对final变量的赋值语句;

    [java] view plain copy

      1. class Final {  
      2.     private final valueOne;  
      3.       
      4.     public Final() {  
      5. 1;  
      6.     }  
      7.       
      8.     public Final(int xx) {  
      9. 1;  
      10.     }  
      11. }

       

       

      4.不能同时在非静态语句块和构造方法中对final赋值,因为只能初始化一次,但是语句块总是和构造方法一同执行。

       

      总之记住一点:final修饰的变量在使用之前,必须初始化,只有三个地方可以初始化:

       a.定义处初始化;

       b.语句块中初始化;

       c.构造方法中初始化。
       

      final还可以修饰参数,无法修改参数的值或者引用。

      [java] view plain copy

        1. public void noChangeParam(final Refe ref,final int a) {  
        2. //不能修改
        3. //a = 3;
        4. //ref = new Refe(22);
        5. }

         

        二 final方法

        final修饰方法时包含的语义是:该方法禁止重写。注意,可以重载。

        有一点值得我们特别注意:类中所有的private方法都隐式的指定为final,也就是子类中无法覆盖它。其实这也很好理解,private不具有子类继承性,所以子类也就不存在覆盖它的可能。但是如果对private方法显示的添加final修饰词(虽然这没有任何意义),但是这可能会造成混淆。

        [java] view plain copy

        1. class WithFinals {  
        2.       
        3.     private final void f() {  
        4. "WithFinal.f()");  
        5.     }  
        6.       
        7.     private void g() {  
        8. "WithFinal.g()");  
        9.     }  
        10. }  
        11. /*
        12.  * 看起来子类好像覆盖了父类的private方法和private final方法
        13.  */
        14. class OverridingPrivate extends WithFinals {  
        15.   
        16.     private final void f() {  
        17. "OverridingPrivate.f()");  
        18.     }  
        19.       
        20.     private void g() {  
        21. "OverridingPrivate.g()");  
        22.     }  
        23. }

         

         

        看起来子类覆盖了父类中的private final方法,这怎么可能呢?!这又该如何解释呢?

        我们一定要正确理解覆盖的意思,“覆盖”只有在某个方法是父类接口的一部分时才会出现,也就是说这个方法必须是子类可以看见的,这样子类向上转型为父类时,可以通过调用这个方法。但是当方法是private时,它就不是父类接口的一部分,它只是父类私有的,子类看不见。这个时候子类完全可以生成一个具有同样签名的方法,它也仅仅是恰巧有着同样的方法签名而已,并不是覆盖。

         

        三 final类

        final类无法继承,final类中的方法也就不存在覆盖的问题了,所以final类中的所有方法都隐式的指定为final。