1. 程式人生 > 其它 >JAVA繼承與多型

JAVA繼承與多型

第一節、繼承

一、繼承的概念、格式、特點

(一)繼承的概念:

1、繼承是多型的前提,如果沒有繼承,就沒有多型。

2、繼承解決的主要問題是:共性抽取。

3、面向物件的三大特徵:封裝性、繼承性、多型性。

(二)繼承的格式

父類的格式:(即普通類)

public class 父類名稱 {
// ...

}

子類的格式:

public class 子類名稱 extends 父類名稱 {
// ...

}

(三)繼承的三個特點(單繼承、多層繼承、相對繼承)

1、Java只支援單繼承,不支援多繼承。

2、Java支援多層繼承(繼承體系)。

3、子類和父類是一種相對的概念。

二、繼承中的變數

(一)成員變數的訪問(直接、間接)

在父子類的繼承關係當中,如果成員變數重名,則建立子類物件時,訪問有兩種方式:

1、直接通過子類物件訪問成員變數:

等號【左邊】是誰,就優先用誰,沒有則向上找。

2、間接通過成員方法訪問成員變數:

該方法【屬於】誰,就優先用誰,沒有則向上找。

(二)子類方法中重名的三種變數區分(區域性、本成、父成)

1、區域性變數: 直接寫局員變數名

2、本類的成員變數: this.成員變數名

3、父類的成員變數: super.成員變數名

三、繼承中的方法

(一)成員方法-覆蓋重寫

1、訪問:在父子類的繼承關係當中,建立子類物件,訪問成員方法的規則:建立的物件是誰,就優先用誰,如果沒有則向上找。

注意事項:

無論是成員方法還是成員變數,如果沒有都是向上找父類,絕對不會向下找子類的。

重寫(Override):方法的名稱一樣,引數列表【也一樣】。覆蓋、覆寫。

過載(Overload):方法的名稱一樣,引數列表【不一樣】。

2、重寫(Override)

概念:重寫要求兩同兩小一大原則: 方法名相同,引數型別相同,子類返回型別小於等於父類方法返回型別, 子類丟擲異常小於等於父類方法丟擲異常, 子類訪問許可權大於等於父類方法訪問許可權。

(1)必須保證父子類之間方法的名稱相同,引數列表也相同。

@Override:寫在方法前面,用來檢測是不是有效的正確覆蓋重寫。

這個註解就算不寫,只要滿足要求,也是正確的方法覆蓋重寫。

(2)子類方法的返回值型別必須【小於等於】父類方法的返回值型別。

小擴充套件提示:java.lang.Object類是所有類的公共最高父類(祖宗類),java.lang.String就是Object的子類。

(3)子類方法的丟擲異常【小於等於】父類方法的丟擲異常

(4)子類方法的許可權必須【大於等於】父類方法的許可權修飾符。

小擴充套件提示:public > protected > (default) > private

備註:(default)不是關鍵字default,而是什麼都不寫,留空。

(二)構造方法的訪問

1、繼承關係中,父子類構造方法的訪問特點:

(1) 子類構造方法當中有一個預設隱含的“super()”呼叫,所以一定是先呼叫的父類構造,後執行的子類構造。

(2)子類構造可以通過super關鍵字來呼叫父類過載構造。

(3)super的父類構造呼叫,必須是子類構造方法的第一個語句。不能一個子類構造呼叫多次super構造。

(4)子類必須呼叫父類構造方法,不寫則贈送super();寫了則用寫的指定的super呼叫,super只能有一個,還必須是第一個。

(5)父類的構造方法是不被子類繼承的,只能從子類的構造方法中用super關鍵字呼叫。

四、super與this關鍵字

(一)super三用法

1、在子類的成員方法中,訪問父類的成員變數。

2、在子類的成員方法中,訪問父類的成員方法。

3、在子類的構造方法中,訪問父類的構造方法。

(二)this三用法

1、在本類的成員方法中,訪問本類的成員變數。

2、在本類的成員方法中,訪問本類的另一個成員方法。

3、在本類的構造方法中,訪問本類的另一個構造方法。

在第3種用法當中要注意:

A. this( )呼叫也必須是構造方法的第一個語句,唯一一個。

B. super和this兩種構造呼叫,不能同時使用。

(三)super與this的記憶體圖解

五、繼承綜合案例:發紅包

(一)案例分析

(二)案例實現

第二節、抽象類

一、抽象的概念、格式

(一)概念

1、父類中的方法,被它的子類們重寫,子類各自的實現都不盡相同。那麼父類的方法宣告和方法主體,只有宣告還有意義,而方法主體則沒有存在的意義了。我們把沒有方法主體的方法稱為抽象方法。Java語法規定,包含抽象方法的類就是抽象類。

2、被abstract修飾的內容都是暫未被實現的,比如類、方法。

屬性之所以不能被abstract修飾,是因為屬性不存在"尚未被實現"的狀態。

比如你可能會聯想到int age; 或是String name; 但可惜的是,在申明變數時,int會預設給age賦予初始值0,String會預設給name賦予初始值""。因此屬性達不到"尚未被實現的狀態",從而不能被abstract修飾。

(二)抽象方法和抽象類的格式

抽象方法:就是加上abstract關鍵字,然後去掉大括號,直接分號結束。

抽象類:抽象方法所在的類,必須是抽象類才行。在class之前寫上abstract即可。

二、抽象的使用、注意事項

(一)如何使用抽象類和抽象方法:

1、不能直接建立new抽象類物件。

2、必須用一個子類來繼承抽象父類。

3、子類必須覆蓋重寫抽象父類當中所有的抽象方法。

覆蓋重寫(實現):子類去掉抽象方法的abstract關鍵字,然後補上方法體大括號。

4、建立子類物件進行使用。

(二)抽象方法和抽象類的注意事項

1、抽象類不能建立物件,如果建立,編譯無法通過而報錯。只能建立其非抽象子類的物件。

理解:假設建立了抽象類的物件,呼叫抽象的方法,而抽象方法沒有具體的方法體,沒有意義。

2、抽象類中,可以有構造方法,是供子類建立物件時,初始化父類成員使用的。

理解:子類的構造方法中,有預設的super(),需要訪問父類構造方法。

3、抽象類中,不一定包含抽象方法,但是有抽象方法的類必定是抽象類。

理解:未包含抽象方法的抽象類,目的就是不想讓呼叫者建立該類物件,通常用於某些特殊的類結構設計。

4、抽象類的子類,必須重寫抽象父類中所有的抽象方法,否則,編譯無法通過而報錯。除非該子類也是抽象類。

理解:假設不重寫所有抽象方法,則類中可能包含抽象方法。那麼建立物件後,呼叫抽象的方法,沒有意義。

第三節、介面

一、介面的概念、格式、特點

(一)介面的概念

1、介面,是Java語言中一種引用型別,是方法的集合,如果說類的內部封裝了成員變數、構造方法和成員方法,那麼 介面的內部主要就是封裝了方法,包含抽象方法(JDK 7及以前),預設方法和靜態方法(JDK 8),私有方法 (JDK 9)。 介面的定義,它與定義類方式相似,但是使用 interface 關鍵字。它也會被編譯成.class檔案,但一定要明確它並 不是類,而是另外一種【引用資料型別】。

2、介面的使用,它不能建立物件,但是可以被實現( implements ,類似於被繼承)。一個實現介面的類(可以看做是介面的子類),需要實現介面中所有的抽象方法,建立該類物件,就可以呼叫方法了,否則它必須是一個抽象類。

3、介面是一種特殊的抽象類。

(二)介面的格式

public interface 介面名稱 {
// 介面內容

}

(三)介面的特點

1、內容特點:

抽象方法(JDK 7及以前),預設方法和靜態方法(JDK 8),私有方法 (JDK 9)

在Java9+版本中,介面的內容可以有:

(1)成員變數其實是常量,格式:

[public] [static] [final] 資料型別 常量名稱=資料值;

注意:常量必須進行賦值,而且一旦賦值不能改變。常量名稱完全大寫,用下劃線進行分隔。

(2)介面中最重要的就是抽象方法,格式:

[public] [abstract] 返回值型別 方法名稱(引數列表);

注意:實現類必須覆蓋重寫介面所有的抽象方法,除非實現類是抽象類。

(3)從Java8開始,接口裡允許定義預設方法,格式:

[public] default 返回值型別 方法名稱(引數列表){方法體}

注意:預設方法也可以被覆蓋重寫

(4)從Java8開始,接口裡允許定義靜態方法,格式:

[public] static 返回值型別 方法名稱(引數列表){方法體}

注意:應該通過介面名稱進行呼叫,不能通過實現類物件呼叫介面靜態方法

(5)從Java9開始,接口裡允許定義私有方法,格式:

普通私有方法:private 返回值型別 方法名稱(引數列表){方法體}

靜態私有方法:private static 返回值型別 方法名稱(引數列表){方法體}

注意:private的方法只有介面自己才能呼叫,不能被實現類或別人使用。

2、實現特點(多實現)

(1)類與類之間是單繼承的。直接父類只有一個。

(2)類與介面之間是多實現的。一個類可以實現多個介面。

(3)介面與介面之間是多繼承的。

注意事項:

①多個父介面當中的抽象方法如果重複,沒關係,不衝突因為抽象方法沒有方法體。

②多個父介面當中的預設方法如果重複,那麼子介面必須進行預設方法的覆蓋重寫,【而且帶著default關鍵字】。

二、介面的常量

(一)格式

public static final 資料型別 常量名稱 = 資料值;

備註:一旦使用final關鍵字進行修飾,說明不可改變。

(二)特點

介面當中也可以定義“成員變數”,但是必須使用public static final三個關鍵字進行修飾。

從效果上看,這其實就是介面的【常量】。

注意事項:

1、介面當中的常量,可以省略public static final,注意:不寫也照樣是這樣。

2、介面當中的常量,必須進行賦值;不能不賦值。

3、介面中常量的名稱,使用完全大寫的字母,用下劃線進行分隔。(推薦命名規則)

三、介面的四類方法(抽、默、靜、私)

(一)抽象方法abstract

1、介面抽象方法定義

在任何版本的Java中,介面都能定義抽象方法。

格式:

public abstract 返回值型別 方法名稱(引數列表);

注意事項:

(1)介面當中的抽象方法,修飾符必須是兩個固定的關鍵字:【public abstract】

(2)這兩個關鍵字修飾符,可以選擇性地省略。

(3)方法的三要素(返回值型別,方法名稱,引數列表),可以隨意定義。

2、介面抽象方法使用

介面使用步驟:

(1)介面不能直接使用,必須有一個“實現類”來“實現”該介面。

格式:

public class 實現類名稱 implements 介面名稱 {
// ...

}

(2)介面的實現類必須覆蓋重寫(實現)介面中所有的抽象方法。

實現:去掉abstract關鍵字,加上方法體大括號。

(3)建立實現類的物件,進行使用。

注意事項:

如果實現類並沒有覆蓋重寫介面中所有的抽象方法,那麼這個實現類自己就必須是抽象類。

(二)預設方法default (介面升級)

1、介面預設方法定義

從Java 8開始,接口裡允許定義預設方法。

格式:

public default 返回值型別 方法名稱(引數列表) {
方法體

}

備註:介面當中的預設方法,可以解決【介面升級】的問題。

2、介面預設方法使用

(1)介面的預設方法,可以通過介面【實現類物件】,直接【呼叫】。

(2)介面的預設方法,也可以被介面【實現類】進行覆蓋【重寫】。

(三)靜態方法static

1、介面靜態方法定義

從Java 8開始,介面當中允許定義靜態方法。

格式:

public static 返回值型別 方法名稱(引數列表) {
方法體

}

提示:就是將abstract或者default換成static即可,帶上方法體。

2、介面靜態方法使用

通過介面名稱,直接呼叫其中的靜態方法。

注意事項:不能通過介面實現類的物件來呼叫介面當中的靜態方法。

格式:

介面名稱.靜態方法名(引數);

(四)私有方法private / private static

1、接囗私有方法定義

從Java 9開始,介面當中允許定義私有方法:

(1)普通私有方法,解決多個【預設方法】之間【重複程式碼】問題

格式:

private 返回值型別 方法名稱(引數列表) {
方法體

}

(2)靜態私有方法,解決多個【靜態方法】之間【重複程式碼】問題

格式:

private static 返回值型別 方法名稱(引數列表) {
方法體

}

四、繼承父類並實現多個介面

(一)介面是沒有靜態程式碼塊或者構造方法的。

(二)一個類的直接父類是唯一的,但是一個類可以同時實現多個介面。

格式:

public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆蓋重寫所有抽象方法

}

(三)如果實現類所實現的多個介面當中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。

(四)如果實現類沒有覆蓋重寫所有介面當中的所有抽象方法,那麼實現類就必須是一個【抽象類】。

(五)如果實現類所實現的多個介面當中,存在重複的預設方法,那麼實現類一定要對衝突的預設方法進行覆蓋重寫。

(六)一個類如果直接父類當中的方法,和介面當中的預設方法產生了衝突,優先用【父類】當中的方法。

第四節、多型

一、多型的概念、格式、特點

(一)多型的概念

1、多型: 是指同一行為,具有多個不同表現形式。父類引用指向子類物件,引用變數所呼叫的方法總是表現出子類方法的行為特徵。

2、多型的前提【重點】

(1)繼承或者實現【二選一】

(2)方法的重寫【意義體現:不重寫,無意義】

(3)父類引用指向子類物件【格式體現】

(二)多型的格式

程式碼當中體現多型性,其實就是一句話:父類引用指向子類物件。(一隻貓被看做成一隻動物)

格式:

父類名稱 物件名 = new 子類名稱();

或者:

介面名稱 物件名 = new 實現類名稱();

(三)多型中的特點

1、成員變數(編譯執行全看父類)

成員變數不能覆蓋重寫

成員變數不具備多型性,通過引用變數來訪問其包含的例項變數,系統總是試圖訪問它編譯時型別所定義的成員變數,而不是執行時型別所定義的成員變數。

什麼是編譯時型別和執行時型別?

Java中的許多物件(一般都是具有父子類關係的父類物件)在執行時都會出現兩種型別:編譯時型別和執行時型別,例如:Person person = new Student();這行程式碼將會生成一個person變數,該變數的編譯時型別是Person,執行時型別是Student。

Java的引用變數有兩個型別,一個是編譯時型別,一個是執行時型別,編譯時型別由宣告該變數時使用的型別決定,執行時型別由實際賦給該變數的物件決定。如果編譯時型別和執行時型別不一致,會出現所謂的多型。因為子類其實是一種特殊的父類,因此java允許把一個子類物件直接賦值給一個父類引用變數,無須任何型別轉換,或者被稱為向上轉型,由系統自動完成。

有一些父類,他允許被繼承,但是他本身有一些屬於自己的函式,這些函式也允許覆蓋,但是函式中有一些自己必須要執行的步驟,如果不執行就會導致類錯誤,所以我們在覆蓋這些函式的時候,必須呼叫super.xxx。讓父函式正常執行,才能執行我們覆蓋後新增的內容。

2、成員方法(編譯看父類,執行看子類)

在多型的程式碼當中,成員方法的訪問規則是:

看new的是誰,就優先用誰,沒有則向上找。

口訣:編譯看左邊,執行看右邊。

對比一下:

成員變數:編譯看左邊,執行還看左邊。***

成員方法:編譯看左邊,執行看右邊。

3、多型的好處

二、多型的轉型(向上、向下)

(一)物件的向上轉型

向上轉型一定是安全的,沒有問題的,正確的。但是也有一個弊端:

物件一旦向上轉型為父類,那麼就無法呼叫子類原本特有的內容。

解決方案:用物件的向下轉型【還原】。

(二)物件的向下轉型

三、用instanceof關鍵字進行父子類判斷

如何才能知道一個父類引用的物件,本來是什麼子類?

格式:

物件 instanceof 類名稱

這將會得到一個boolean值結果,也就是判斷前面的物件能不能當做後面型別的例項。

四、多型案例筆記本USB

(一)筆記本USB介面案例分析

(二)筆記本USB介面案例實現

第五節、fina關鍵字

一、fina關鍵字概念

(一)final關鍵字概念

學習了繼承後,我們知道,子類可以在父類的基礎上改寫父類內容,比如,方法重寫。那麼我們能不能隨意的繼承 API中提供的類,改寫其內容呢?顯然這是不合適的。為了避免這種隨意改寫的情況,Java提供了 final 關鍵字, 用於修飾不可改變內容。

final: 不可改變。可以用於修飾類、方法和變數。

類:被修飾的類,不能被繼承。

方法:被修飾的方法,不能被重寫。

變數:被修飾的變數,不能被重新賦值

(二)常見四種用法:

1. 可以用來修飾一個類

2. 可以用來修飾一個方法

3. 還可以用來修飾一個區域性變數

4. 還可以用來修飾一個成員變數

二、final的4種用法(類、局變、成變、成方)

(一)final修飾類

當final關鍵字用來修飾一個類的時候,格式:

public final class 類名稱 {
// ...

}

含義:當前這個類不能有任何的子類。(太監類)

注意:一個類如果是final的,那麼其中所有的成員方法都無法進行覆蓋重寫(因為沒兒子。)

(二)final修飾區域性變數

(三)final修飾成員變數

1、由於成員變數具有預設值,所以用了final之後必須手動賦值,不會再給預設值了。

2、對於final的成員變數,要麼使用直接賦值,要麼通過構造方法賦值。二者選其一。

3、必須保證類當中所有過載的構造方法,都最終會對final的成員變數進行賦值。

(四)final修飾成員方法

當final關鍵字用來修飾一個方法的時候,這個方法就是最終方法,也就是不能被覆蓋重寫。

格式:

修飾符 final 返回值型別 方法名稱(引數列表) {
// 方法體

}

注意事項:

對於類、方法來說,abstract關鍵字和final關鍵字不能同時使用,因為矛盾。

第六節、許可權修飾符

編寫程式碼時,如果沒有特殊的考慮,建議這樣使用許可權:

成員變數使用 private ,隱藏細節。

構造方法使用 public ,方便建立物件。

成員方法使用 public ,方便呼叫方法。

第七節、內部類

一、內部類的概念

(一)內部類的概念

如果一個事物的內部包含另一個事物,那麼這就是一個類內部包含另一個類。

例如:身體和心臟的關係。又如:汽車和發動機的關係。

(二)分類:

1、成員內部類

2、區域性內部類(包含匿名內部類)

二、成員內部類

(一)成員內部類的格式

修飾符 class 外部類名稱 {
修飾符 class 內部類名稱 {
// ...

}

// ...

}

注意:內用外,隨意訪問;外用內,需要內部類物件。

(二)成員內部類的訪問特點

1. 間接方式:在外部類的方法當中,使用內部類;然後main只是呼叫外部類的方法。

2. 直接方式,

類名稱 物件名 = new 類名稱();

【 外部類名稱.內部類名稱 物件名 = new 外部類名稱().new 內部類名稱(); 】

(三)成員內部類的同名變數訪問

如果出現了重名現象,那麼格式是:外部類名稱.this.外部類成員變數名

三、區域性內部類

(一)區域性內部類的格式

如果一個類是定義在一個方法內部的,那麼這就是一個區域性內部類。

“區域性”:只有當前所屬的方法才能使用它,出了這個方法外面就不能用了。

定義格式:

修飾符 class 外部類名稱 {
修飾符 返回值型別 外部類方法名稱(引數列表) {
class 區域性內部類名稱 {
// ...

}

}

}

類的許可權修飾符:

public > protected > (default) > private

定義一個類的時候,許可權修飾符規則:

1、外部類:public / (default)

2、成員內部類:public / protected / (default) / private

3、區域性內部類:什麼都不能寫

(二)區域性內部類的final問題

區域性內部類,如果希望訪問所在方法的區域性變數,那麼這個區域性變數必須是【有效final的】。

備註:從Java 8+開始,只要區域性變數事實不變,那麼final關鍵字可以省略。

原因:

1、new出來的物件在堆記憶體當中。

2、區域性變數是跟著方法走的,在棧記憶體當中。

3、方法執行結束之後,立刻出棧,區域性變數就會立刻消失。

4、但是new出來的物件會在堆當中持續存在,直到垃圾回收消失。

(三)區域性內部類重點:【匿名內部類】

1、匿名內部類的格式

如果介面的實現類(或者是父類的子類)只需要使用唯一的一次,

那麼這種情況下就可以省略掉該類的定義,而改為使用【匿名內部類】。

匿名內部類的定義格式:

介面名稱 物件名 = new 介面名稱() {
// 覆蓋重寫所有抽象方法

.....

};

2、匿名內部類的注意事項

對格式“new 介面名稱() {...}”進行解析:

(1)new代表建立物件的動作

(2)介面名稱就是匿名內部類需要實現哪個介面

(3) {...}這才是匿名內部類的內容

另外還要注意幾點問題:

(1)匿名內部類,在【建立物件】的時候,只能使用唯一一次。

如果希望多次建立物件,而且類的內容一樣的話,那麼就需要使用單獨定義的實現類了。

(2)匿名物件,在【呼叫方法】的時候,只能呼叫唯一一次。

如果希望同一個物件,呼叫多次方法,那麼必須給物件起個名字。

(3)匿名內部類是省略了【實現類/子類名稱】,但是匿名物件是省略了【物件名稱】

強調:匿名內部類和匿名物件不是一回事!!!

第八節、引用型別用法總結

一、calss作為成員變數型別

二、interface作為成員變數、方法引數、返回值型別


————————————————
版權宣告:本文為CSDN博主「91健」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/qq_21550473/article/details/100567827