Java學習筆記18---final關鍵字來修飾變數、方法及類

来源:http://www.cnblogs.com/chanchan/archive/2017/12/01/7936388.html
-Advertisement-
Play Games

英語里final這個單詞大家都知道是“最終的”意思,其實還有一個意思是“不可更改的”。在Java里,final關鍵字作“不可更改的”來解釋更合適,即由final修飾的東西是“不可更改的”。final可以修飾變數、成員方法和類,還可以修飾方法的參數,但參數歸根結底還是變數。下麵是詳細解釋。 作者: 蟬 ...


英語里final這個單詞大家都知道是“最終的”意思,其實還有一個意思是“不可更改的”。在Java里,final關鍵字作“不可更改的”來解釋更合適,即由final修飾的東西是“不可更改的”。final可以修飾變數、成員方法和類,還可以修飾方法的參數,但參數歸根結底還是變數。下麵是詳細解釋。


作者: 蟬蟬

請尊重作者勞動成果,轉載請在標題註明“轉載”字樣,並標明原文鏈接:

http://www.cnblogs.com/chanchan/p/7936388.html 

 

1.final可以修飾成員變數、局部變數

(1).final修飾的變數的值不能更改,即不能再次賦值,即使賦的新值與舊值一樣也不可以。

如:

      final int i = 1; //定義int型變數i,並賦初值為1

      //i = 2; //wrong

      //i = 1; //wrong

註釋掉的這兩行都不可以,都會出現“The final local variable i can not be assigned.It must be blank and not using a compound assignment.”的錯誤。

(2).final修飾的成員變數和局部變數需要在使用前賦值。

    1).對成員變數而言,可以在定義時直接賦初值;

    2).也可以先定義不賦初值,再在構造方法中對其賦值。

就是說,對象創建好後,該對象的final成員變數要保證是賦了初值的,早點(定義時賦值)、晚點(在構造方法里賦值)都沒關係。

註:第二種情況,如果有多個構造方法就比較麻煩了,每個構造方法都要有賦值語句,否則會出現“The blank final field height may not have been initialized.”的錯誤。

      3).如果靜態成員變數被修飾為final,那麼該變數可看成是全局變數,即在類的整個載入期間,其值都不可變。

          如:

          static final String citizenship = "Chinese";

          citizenship既是static又是final的,static說明它是屬於整個類的,類載入時就分配記憶體了(參見筆記9),final說明其值不可變,即,位置固定內容也固定。

(3).把成員變數和局部變數從變數的類型上來分,

    1).當變數為基本數據類型時,變數的值不可更改,如上面的變數i;

    2).當變數為引用類型時,變數本身的值不可更改,即該變數不能指向其他的對象或數組;

        但該變數指向的對象或數組本身的內容是可以改變的

        如:

            final Person per = new Person(); //定義了一個Person類的對象引用per,並指向了new的對象

            //per = new Person(); //重新創建一個Person類對象,並讓per指向它,會出現與上面一樣的錯誤,即final修飾的引用類型變數不能重新賦值

            per.name = "me"; //per指向的對象本身的內容可以更改

 

為方便理解起見,請參考下麵的記憶體圖:

 

2.final可以修飾成員方法

(1).final修飾的成員方法不能被子類重寫,即,當父類的方法為final時,子類不能與父類有方法名、參數類型、參數個數及參數順序都一樣的方法;父類方法為private時除外,詳見下麵的(3);但子類可以調用父類的final方法。

見下麵的代碼:

Person類的方法:
    final void finalMethod() {
        int i = 2;
        System.out.println("finalMethod: i = " + i);
    }

在TestMain中由Student類的對象引用調用:
public class TestMain {
    public static void main(String[] args) {
        Student stu = new Student();
        
        stu.finalMethod();
}

輸出結果為:finalMethod: i = 2

(2).訪問許可權為private的方法預設為final的,但子類不可以調用private的方法,關於訪問許可權修飾符的問題,詳見筆記10

(3).當父類某方法為private final,子類的成員方法與父類的該成員方法重名但僅由final修飾時,這時算不算重寫呢?

Person類的方法:
    private final void priFinalMethod() {
        System.out.println("Person:priFinalMethod");
    }

Student類的方法:
    final void priFinalMethod() {
        System.out.println("Student:priFinalMethod");
    }

TestMain類:
package human;

public class TestMain {
    public static void main(String[] args) {
        Person per = new Person();
        Student stu = new Student();
        Person per1 = stu;
        
//        per.priFinalMethod();
        stu.priFinalMethod();
//        per1.priFinalMethod();
}

Person類的main方法:
    public static void main(String[] args) {
        Person per = new Person();
        Student stu = new Student();
        Person per1 = stu;
        
        per.priFinalMethod();
        stu.priFinalMethod();
        per1.priFinalMethod();
}

TestMain類的輸出是:

Student:priFinalMethod

    1).其中,TestMain類中註釋掉的兩行都提示該方法不可見;

    2).對於per來說,private的方法僅本類可見,在TestMain類中是不可見的,所以per是不能調用priFinalMethod方法的;

    3).對於per1來說,per1是指向Student對象的引用,per1只能調用Student中重寫過的方法及Person類中的方法,由於這裡仍然提示該方法不可見,結合2)可知,priFinalMethod方法是沒被子類重寫的,否則就可以調用了;

 

Person類的輸出是:

Person:priFinalMethod
Student:priFinalMethod
Person:priFinalMethod

前兩行好理解,最後一行,per1調用的是Person類中的priFinalMethod,進一步說明該方法未被子類重寫;

否則,會優先調用子類的priFinalMethod方法的。

 

3.final可以修飾成員方法的參數

由final修飾的成員方法的參數也是不能更改的,其實參數就是變數,具體參見1即可。

這裡還涉及到形參與實參的概念,具體大家自己瞭解吧。

 

4.final可以修飾類

由final修飾的類不能被子類繼承,其成員方法也預設為final的,但成員變數是可以改變的,見下麵代碼:

package human;

public final class FinalClass {

    int i = 1;
    
    void test() {
        System.out.println("FinalClass:test");
    }
    
    public static void main( String[] args ) {
        FinalClass ficl = new FinalClass();
        
        System.out.println("ficl.i = " + ficl.i);
        ficl.i = 2;
        System.out.println("ficl.i = " + ficl.i);
    }
}

輸出結果為:

ficl.i = 1
ficl.i = 2

可見可以修改i的值。

 

附測試源碼:

Person類:

package human;

public class Person {
//class Person{
    String name;
    int age;
    String gender;
    
    //筆記18:final修飾成員變數,及成員變數為類引用時的情況
    final int height = 160;
//    final int height;
    final EduBackground edu = new EduBackground();
    
    public Person() {
//  final height = 160;
    }
    
//筆記18:final修飾局部變數、修飾成員方法、修飾方法的參數
    //修飾局部變數時,局部變數的值不能改變
    void finalLocal() {
//        final int i = 1;
        final int i;
        
//        i = 3;
        final EduBackground edu = new EduBackground();
//        edu = new EduBackground();
        i = 1;
        System.out.println("finalLocal: i = " + i);
    }
    
    //修飾方法的參數時,參數不能被修改
    void finalArgs(final int i) {
//        i = 3;
        System.out.println("finalArgs: i = " + i);
    }
    void finalArgs(final EduBackground edu) {
//        edu = new EduBackground();
        System.out.println("finalArgs: edu");
    }
    
    //修飾成員方法時,成員方法不能被子類重寫
    final void finalMethod() {
        int i = 2;
        System.out.println("finalMethod: i = " + i);
    }
    private final void priFinalMethod() {
        System.out.println("Person:priFinalMethod");
    }

    public static void main(String[] args) {
        Person per = new Person();
        Student stu = new Student();
        Person per1 = stu;
        
        per.priFinalMethod();
        stu.priFinalMethod();
        per1.priFinalMethod();
    }
}

 

Student類:

package human;

public class Student extends Person {
    String stuNumber;
    int score;
    
    public Student() {
        
    }
        
//筆記18:子類不能重寫父類被final修飾的方法
//    final void finalMethod() {
//        int i = 2;
//        System.out.println("finalMethod: i = " + i);
//    }
    final void priFinalMethod() {
        System.out.println("Student:priFinalMethod");
    }

}

EduBackground類:
package human;

//public class EduBackground extends FinalClass {
public class EduBackground {

    String primarySchool;
    String secondarySchool;
    String juniorHSchool;
    String seniorHSchool;
    String university;
    
    public EduBackground() {
        
    }
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...