Java學習筆記——第十一天

zgg1h發表於2024-03-10

物件導向高階(二)

多型

多型是在繼承/實現情況下的一種現象,表現為:物件多型、行為多型。

多型的具體程式碼體現

//使用同一個類名建立了不同型別的物件,體現了物件多型
People p1 = new Student();
People p2 = new Teacher();
//不同型別的物件呼叫了同一個名字的方法,體現了行為多型
p1.run();
p2.run();

識別技巧:編譯看左邊,行為看右邊

多型的前提

  • 有繼承/實現關係。

  • 存在父類引用子類物件。

  • 存在方法重寫。

多型的注意事項

  • 多型是物件、行為的多型,Java中的屬性(成員變數)不談多型。
  • 多型的物件作為引數傳入方法時,是看建立時的等號左邊;而使用.呼叫方法時,是看等號右邊。

多型有什麼用

  • 在多型形式下,右邊物件是解耦合(松耦合)的,更便於擴充套件和維護。

  • 定義方法時,使用父類型別的形參,可以接收一切子類物件,擴充套件性更強、更便利。

多型的問題

  • 多型下不能使用子類的獨有功能。

  • 可以使用強制型別轉換,把物件轉換成其真正的型別,從而解決多型下不能呼叫子類獨有方法的問題。

多型下的型別轉換問題

型別轉換

自動型別轉換:

父類 變數名 = new 子類(); 

強制型別轉換:

子類 變數名 = (子類) 父類變數;

強制型別轉換的一個注意事項

  • 存在繼承/實現關係就可以在編譯階段進行強制型別轉換,編譯階段不會報錯。
  • 執行時,如果發現物件的真實型別與強轉後的型別不同,就會報型別轉換異常(ClassCastException)的錯誤出來。
  • Java建議:強轉前,使用instanceof關鍵字,判斷當前物件的真實型別,再進行強轉。

final

final 關鍵字是最終的意思,可以修飾類、方法和變數。

  1. 修飾類:該類被稱為最終類,特點是不能被繼承了。
  2. 修飾方法:該方法被稱為最終方法,特點是不能被重寫了。
  3. 修飾變數:該變數只能被賦值一次,且當修飾成員變數時必須要在定義時同時賦值。

final修飾變數的注意事項

  • final修飾基本型別的變數,變數儲存的資料不能被改變。
  • final修飾引用型別的變數,變數儲存的地址不能被改變,但地址所指向物件的內容是可以被改變的。

變數的分類

變數:

  1. 區域性變數

  2. 成員變數:

    1. 靜態成員變數
    2. 例項成員變數

常量

  • 使用了static final修飾的成員變數就被稱為常量。其作用是通常用於記錄系統的配置資訊。

  • 常量名的命名規範:建議使用大寫英文單詞,多個單詞使用下劃線連線起來。

常量的好處

  • 程式碼可讀性更好,可維護性也更好。
  • 程式編譯後,常量會被“宏替換”:出現常量的地方全部會被替換成其記住的字面量,這樣可以保證使用常量和直接用字面量的效能是一樣的。

抽象類

使用關鍵字abstract修飾類,這個類就是抽象類;修飾方法,這個方法就是抽象方法。

格式

修飾符 abstract class 類名{ 
	修飾符 abstract 返回值型別 方法名稱(形參列表);
 }

抽象類的注意事項和特點

  • 抽象類中不一定有抽象方法,有抽象方法的類一定是抽象類。
  • 類有的成員(成員變數、方法、構造器、程式碼塊和內部類)抽象類都可以有。
  • 抽象類最主要的特點:抽象類不能建立物件,僅作為一種特殊的父類,讓子類繼承並實現。
  • 一個類繼承抽象類,必須重寫完抽象類的全部抽象方法,否則這個類也必須定義成抽象類。

抽象類的應用場景和好處

抽象類由兩種主要的應用場景:

  1. 用抽象類,我們可以把子類中相同的程式碼,包括方法簽名都抽上來,這樣能更好的支援多型,以提高程式碼的靈活性,並且減少重複程式碼的書寫,提高開發效率。
  2. 反過來用,我們不知道系統未來具體的業務實現時,我們可以先定義抽象類,將來讓子類去繼承實現,以方便系統的擴充套件。

抽象類的常見應用場景

經常用來設計模板方法設計模式。

模板方法設計模式解決了什麼問題

解決方法中存在重複程式碼的問題。

模板方法設計模式的寫法

  1. 定義一個抽象類。
  2. 在裡面定義2個方法:
    1. 一個是模板方法:把相同程式碼放裡面去。
    2. 一個是抽象方法:具體實現交給子類完成。
  3. 定義子類繼承抽象類,重寫抽象方法。
  4. 建立子類物件,呼叫模板方法完成功能。
  • 建議使用final關鍵字修飾模板方法,因為:
    • 模板方法是給物件直接使用的,不能被子類重寫。
    • 一旦子類重寫了模板方法,模板方法就失效了。

介面

  • Java提供了一個關鍵字interface,用這個關鍵字我們可以定義出一個特殊的結構:介面。
  • 介面不能建立物件;介面是用來被類實現(implements)的,實現介面的類稱為實現類。
  • 一個類可以實現多個介面,實現類實現多個介面,必須重寫完全部介面的全部抽象方法,否則實現類需要定義成抽象類。
  • 介面只有成員物件和成員方法,且預設是常量和抽象方法。
  • 介面也不能建立物件。
  • 介面不繼承Object類。

介面和實現的格式

介面的格式:

public interface 介面名 {
	// 成員變數(常量)
    // 成員方法(抽象方法)
}

實現的格式:

修飾符 class 實現類 implements 介面1, 介面2, 介面3 , ... {

}

//在實現介面時,可以同時繼承父類,但是需要先寫繼承再寫介面
修飾符 class 實現類 entends 父類 implements 介面1, 介面2, 介面3 , ... {

}

介面的好處

  • 彌補了類單繼承的不足,類可以同時實現多個介面。
  • 讓程式可以面向介面程式設計,這樣既不用關心實現的細節,也可以靈活方便的切換各種實現。
  • 透過面向介面程式設計,別人透過實現類implements的介面,就可以顯性的知道實現類實現的是什麼誰,從而也就可以放心的把實現類當作誰來用了,同時也能提高程式碼的可讀性。

JDK8開始,介面中新增的三種方法

預設方法

預設方法(例項方法)使用default修飾,預設會被加上public修飾,只能使用介面的實現類物件呼叫。

私有方法(JDk9開始才支援的)

私有方法必須用private修飾,只能在介面內部被呼叫。

靜態方法

類方法(靜態方法)使用static修飾,預設會被加上public修飾,只能用介面名來呼叫。

這些方法的作用

增強了介面的能力,更便於專案的擴充套件和維護。

介面的多繼承

介面也可以繼承,一個介面可以同時繼承多個介面。

格式

public interface C extends B, A, ... {
    
}

介面多繼承的作用

便於實現類去實現。

介面的其他注意事項

  • 一個介面繼承多個介面,如果多個介面中存在方法簽名衝突,則此時不支援多繼承。
  • 一個類實現多個介面,如果多個介面中存在方法簽名衝突,則此時不支援多實現。
  • 一個類繼承了父類,又同時實現了介面,父類中和介面中有同名的預設方法,實現類會優先用父類的。
  • 一個類實現了多個介面,多個介面中存在同名且同返回值型別的預設方法,可以不衝突,這個類重寫該方法即可。

相關文章