Java基礎(三)-final關鍵字分析

一 引言

  今天來談談final關鍵字的做用, 雖然有不少博文關於final進行了很深的研究,但仍是要去記錄下談談本身的看法加深下印象。下面直接進入主題:html

二 final關鍵字的做用

  一、被final修飾的類不能被繼承。java

  這一點應該不少人都知道也遇到過,經典案例就是java.lang.String類安全

  還有一些常見的類也是被final所修飾的,以下:ide

  基本類型對應的包裝類型(如java.lang.Integer、java.lang.Long等)、字符相關類(java.lang.StringBuilder、java.lang.StringBuffer)、系統類(java.lang.Class、java.lang.System)等。就列這些其餘就靠本身平時去發現。函數

  那麼問題來了,a、爲何final修飾的類不能被繼承?答:這是Java語法定義的,無法。ui

  b、這樣設計的目的是什麼?答:由於類不須要被拓展類的、實現細節不容許改變,估計是爲了安全考慮吧。this

  二、被final修飾的方法不能被重寫spa

  其實這也是Java語法規定的,無法作解釋。可是仔細回憶,這種狀況跟static關鍵字修飾方法中一個特色相似,也是不能重寫(覆蓋)。設計

  下面咱們看案例(代碼通過本身敲出來的才最有印象):code

class MyClass{
    final void test(){
        System.out.println("FinalClass");
    }
}
class MyClass2 extends MyClass {
    //編譯報錯:Cannot override the final method from MyClass
    public void test(){
        System.out.println("FinalClass"); }
}

    三、被final修飾的變量不能被「改變」

  先說下前提1:被final修飾的變量不像static那樣。它也能夠修飾局部變量。 

  前提2:被final修飾的變量必定要被初始化,不然編譯不經過。

  針對前提,咱們先經過案例證實:

1 public class FinalTest {
2     //編譯失敗,不知足前提2。The blank final field count may not have been initialized
3     final int count;
4     public static void main(String[] args)  {
5         //編譯經過。前提1:被final修飾的變量不像static那樣。它也能夠修飾局部變量。 
6         final int t = 0;
7     }
8 }

  初始化有兩種:直接初始化和在構造函數中初始化(每一個構造函數都要初始化即每一個實例化對象的入口都要進行初始化)。

public class FinalTest {
    //直接初始化
    final int count = 0;
    final int num;
    //構造函數中初始化,若是沒有對num進行初始化,就會編譯錯誤。The blank final field num may not have been initialized
    public FinalTest(){
        num = 0;//註釋這樣就能夠看到錯誤提示信息
    }
    public FinalTest(int t){
        num = 0;
        //this();//這兩行左右開啓同樣纔不會報錯。
    }
}

  迴歸重點,被final修飾的變量,它是什麼不能改變呢?變量值仍是變量的引用仍是二者都不能?看似有點玄乎(是否是本身有些沒考慮到),其實也很簡單(平時多留意就行)。依次舉例證實:

    案例1(以基本類型爲例):

 1 public class FinalTest {
 2     final int count = 0;
 3     
 4     public int getCount () {
 5         //The final field FinalTest.count cannot be assigned
 6         return count ++;
 7     }
 8     
 9     public static void main(String[] args)  {
10         FinalTest t = new FinalTest();
11         System.out.println(t.getCount());
12     }
13 }

  上面代碼中第六行報錯(The final field FinalTest.count cannot be assigned)了,因此能夠得知:對於這種基本類型的變量被final所修飾後,它的值是不能被更改的。
  案例2(以對象爲例):

 1 class Count {
 2     int count = 0;
 3     public int getCount () {
 4         return ++ count;
 5     }
 6 }
 7 
 8 public class FinalTest {
 9     
10     public static void main(String[] args)  {
11         final Count count1 = new Count();
12         final Count count2 = new Count();
13         System.out.println(count1.getCount());
14         System.out.println(count2.getCount());
15         //The final local variable count1 cannot be assigned. It must be blank and not using a compound assignment
16         count1 = count2;
17     }
18 }

  第16行一樣的報錯信息,可是這個就有點不同:對象裏面的成員的值是能夠改變的。因此針對這種對象變量而言,被final修飾後不可變的是變量的引用,而不是變量的內容。

  總結下這點:被final修飾的基本類型變量,它的值是不可變的。被final修飾的引用類型變量,它的引用地址是不可變的,對象裏的內容是可變的。

 

三 final關鍵字的拓展

  一、在匿名類中使用外部內的變量,則該變量必須是final所修飾的。下面案例中第10就會編譯報錯,提示必須是final修飾的變量。

 1 public class FinalTest {
 2     
 3     public static void main(String[] args)  {
 4         int count = 0;
 5         
 6         Thread thread1 = new Thread(new Runnable() {
 7             @Override
 8             public void run() {
 9                 //Cannot refer to the non-final local variable count defined in an enclosing scope
10                 count ++;
11             }
12         });
13     }
14 }

  二、其實final還能夠修飾形參。這樣作的主要目的是防止無心的修改而影響到調用方法外的變量。若是你沒了解這句就說明上面第三點做用你還沒了解。

 1 class Count {
 2     int count = 0;
 3     public int getCount () {
 4         return ++ count;
 5     }
 6 }
 7 
 8 public class FinalTest {
 9     int num = 0;
10     public static void main(String[] args)  {
11         final Count count = new Count();
12         addCount(count);
13         System.out.println(count.count);
14     }
15     public static void addCount(final Count count){
16         count.getCount();
17         //count = new Count();//這種就是篡改。
18     }
19 }

 

  三、final變量與普通變量有什麼區別,何時能夠相等?看下下面代碼,想下代碼輸出什麼。

 1 public class FinalTest2 {
 2 
 3     public static void main(String[] args) {
 4         final String str1 = "test";
 5         final String str2 = getContent();
 6         String str3 = "test";
 7         
 8         String str4 = str1 + "";
 9         String str5 = str2 + "";
10         
11         System.out.println(str3 == str4);
12         System.out.println(str3 == str5);
13     }
14     public static String getContent(){
15         return "test";
16     }
17 }

  輸出後的結果爲true和false。這是爲何呢?解釋下你就清楚這二者的區別了。若是是final修飾直接定義的字符串或者是基本類型,它在編譯期間就會肯定其值,則編譯器會把它當作常量。因此當有使用到它的地方會直接用常量替換。而其餘都是運行時纔會肯定的值因此依然使用變量去計算。在代碼中str2變量,雖然用是final修飾可是它的值要在的運行時才能肯定,因此它至關於普通變量。而str5這種計算方式並非咱們想象的簡單,由於str2在這裏成了普通變量,因此會經過stringBulider去計算整個表達式的值,因此返回也是一個新的str,引用地址變了。因此第12行的輸出爲false;

  四、final與finally 和finalize的區別

   finally是異常處理語句結構的一部分,表示最終執行。

finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,供垃圾收集時的其餘資源回收,例如關閉文件等。

相關文章
相關標籤/搜索