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