一、繼承
1. 概述
- 繼承是面向對象的重要特征之一,當多個類中存在相同的屬性和行為時,將這些內容抽取到單獨一個類中,那多個類中無需再定義這些屬性和行為,只需繼承那個單獨的類即可。
- 單獨的類稱為父類或超類
- 多個類稱為子類
- 例如:
- 貓和老虎都是屬于貓科動物。
- 描述貓、老虎這些對象所創建的類,就是子類;
- 而描述貓科動物這個對象所創建的類,就是父類。
- 類與類之間存在了繼承關系,子類可以直接訪問父類中非私有的屬性和行為,代碼中通過 extends 關鍵字來表示繼承關系。
- 例如:class Son extends Father{}//代碼中的書寫格式
- 注:
- 千萬不能為了獲取其他類中的功能,簡化代碼而去繼承。
- 必須是類與類之間有所屬關系才能繼承。
- 這種所屬關系的表示為 is a
2. 特點
1. 提高了代碼的復用性。
2. 讓類與類之間產生了關系,是多態的前提。
- 注:
- Java 語言中只支持單繼承,不支持多繼承。
- Java 雖然不支持多繼承,但是保留了類似的機制,并且以另一種形式來體現,也就是多實現。
- 例如:一個兒子只能有一個父親。
- 只能單繼承的原因?
- 因為類與類多繼承的話,容易產生安全隱患。
- 例如:當多個父類中定義了相同的功能,但功能的內容不相同時,子類對象就無法確定要運行哪一個父類的功能了。
- 因為類與類多繼承的話,容易產生安全隱患。
3. 應用
-
Java 中雖然不支持多繼承,但是支持多層繼承,也就是繼承體系。
- 例如:兒子繼承父親,父親繼承爺爺等。
- class A{}
- class B extends A{}
- class C extends B{}
- 例如:兒子繼承父親,父親繼承爺爺等。
-
如何使用繼承體系中的功能?
- 想要使用繼承體系,先要查詢繼承體系中父類的描述,因為父類中定義的是該繼承體系中的共性功能,了解共性功能后,就可以知道該體系的基本功能,這個繼承體系就基本可以使用了。
-
具體調用時,需要先創建最子類的對象,原因是?
- 有可能父類不能創建對象;
- 創建子類對象可以使用更多的功能,包括基本的父類共性功能,也包括子類的特有功能。
- 總結:查閱父類功能,創建子類對象使用功能。
-
例如:
-
子父類出現后,類成員(變量、函數、構造函數)的特點:
- 變量
- 如果子類中出現非私有的同名成員變量時,子類要訪問本類中的變量,用 this;子類要訪問父類父類中的同名變量,用 super。
- this 和 super 的使用幾乎一致,并且兩者都存于方法區中。
- this 表示本類對象的引用
- super 表示父類對象的引用
- 函數 —— 重寫(覆蓋)
當子類出現和父類一模一樣的函數時,子類對象調用該函數,會運行子類的函數內容,相當于父類的函數被覆蓋了,這就是函數的一個特性:重寫(覆蓋)。
當子類繼承父類,并且沿襲了父類的功能時,子類雖具備父類的該功能,但是子類中功能的內容卻和父類不一致,這時,無需重新定義新功能,而是使用重寫(覆蓋)這一特性,保留父類的功能,并重寫子類的功能內容,子類中同時想具有父類函數中的內容時,可以使用 super.() 方法。
-
在上面例子中的 Student 類中重寫 sleep() 方法,如下:
-
注:
1. 靜態只能覆蓋靜態。 2. 父類中的私有方法不能被重寫(覆蓋)。 3. 子類重寫(覆蓋)父類,必須保證子類權限大于或等于父類權限,才可以重寫(覆蓋),否則會導致編譯失敗。
-
重寫(覆蓋)與重載的區別:
- 重寫(覆蓋):子父類方法要一模一樣。
- 重載:只看同名函數的參數列表。
- 構造函數
對子類對象進行初始化時,父類的構造函數也會運行,因為子類的每一個構造函數默認第一行都有一條隱式的語句 super();
super():訪問父類中空參數的構造函數,而且子類中所有構造函數默認第一行都是 super();
-
子類為什么一定會訪問父類的構造函數?
- 父類中的數據子類可以直接獲取,子類對象在建立時,需先查看父類中是如何對這些數據進行初始化的,因此子類在對象初始化時,需要先訪問父類中的構造函數。
-
為什么 super() 和 this() 不能在同一個構造函數中?
- 因為不能在同一行。
-
為什么 super() 和 this() 不能在同一行?
- 因為需要先做初始化動作,在子類構造函數中必須有一個 super 語句或 this 語句。
-
注:
- super 語句一定是定義在子類構造函數中的第一行。
- 如果要訪問父類中指定的構造函數,可以通過手動定義 super 語句的方式去指定。
-
總結:
1. 子類中所有構造函數,默認都會訪問父類的空參數構造函數; 2. 子類中每一個構造函數中的第一行都有一句隱式 super(); 語句; 3. 父類沒有空參數構造函數時,子類必須手動定義 super 語句或 this 語句形式去指定要訪問的構造函數; 4. 子類的構造函數第一行也可以手動指定 this 語句去訪問本類中的其它構造函數; 5. 子類中至少會有一個構造函數會訪問父類中的構造函數。
- 變量
-
final 關鍵字
由于繼承的出現,打破了對象的封裝性,使得子類可以隨意重寫(覆蓋)父類的功能,這也是繼承的弊端。為了解決繼承的這個弊端,便出現了 final(最終)關鍵字。
-
final 修飾符的特點:
1. 可以修飾類、函數、變量。 2. final 修飾的類不能被繼承。(可以避免被繼承、被子類重寫父類函數功能) 3. final 修飾的方法不能被重寫。 4. final 修飾的變量是常量,并且只能賦值一次,可以修飾成員變量,也可以修飾局部變量。 5. 內部類定義在類中的局部位置時,只能訪問該局部被 final 修飾的局部變量。
二、抽象
1. 概述
- 從多個事物中將共性的、本質的內容抽取出來,這就是抽象。
- 例如:狗和狼共性都是犬科,犬科就是抽象出來的概念。
- Java 中可以定義沒有方法體的方法,方法的具體實現由子類實現,多個對象如果具有相同功能,但功能的具體內容有所不同,那么在抽取過程中,只抽取功能定義,未抽取功能主體內容,這樣只有功能聲明,沒有功能主體的方法,這樣的方法稱為抽象方法,而含有抽象方法的類稱為抽象類。
- 例如:狗和狼都有吼叫的方法,但是吼叫的內容不一樣,因此抽象出來的犬科雖然有吼叫功能,但是并沒有明確吼叫的實現內容細節。
- 格式:
- abstract 類名 {}
- 子類名 extends 抽象類名 {}
2. 特點
抽象類和抽象方法必須使用 abstract 關鍵字進行修飾。
-
抽象方法只有方法聲明,沒有方法體,定義在抽象類中。
- 格式:修飾符 abstract 返回值類型 函數名(參數列表);
-
抽象類不能被實例化,也就是說不能用 new 創建對象,抽象類是從具體事物抽取出來的,抽象類本身是不具體的,沒有對應的實例。
- 例如:犬科是一個抽象的概念,真正存在的實例是狗和狼。
-
抽象類通過其子類進行實例化,子類必須重寫(覆蓋)抽象類中所有的抽象方法,子類才能實例化,否則該子類也會是抽象類。
注:抽象類中可以存在非抽象方法。
-
例如:
-
3. 抽象類與一般類
-
區別:
- 抽象類不可以實例化。
- 抽象類不能創建對象,但是也有構造函數,提供給子類實例化調用。
- 抽象類比一般類多了抽象方法,抽象類中可以定義抽象方法,也可以定義非抽象方法。
-
注:
- 抽象類中可以不定義抽象方法,使抽象類不被實例化,常用于模塊設計。
- 被 abstract 修飾的函數不能同時被 private、static、final 修飾。
- private:抽象類中的抽象方法需要被子類重寫,而 private 修飾的方法是私有的,不被子類所知,無法重寫。
- static:static 修飾的方法可以直接使用類名調用,不需要使用對象調用,如果 static 使用在抽象方法上就沒有運行的意義了。
- final:final 修飾的類不能有子類,而 abstract 修飾的類一定是一個父類。
-
例如:
三、接口
1. 概述
- 當抽象類中所有的方法都是抽象方法時,該類可以通過接口的形式表示,使用 interface 來表示,子類中使用 implements 來實現,接口可以認為是特殊的抽象類。
- 格式:
- interface 接口名{}
- 子類名 implements 接口名 {}
- 特點:
- 接口中常見定義:常量、抽象方法。
- 接口中成員都是使用 public 修飾的。
- 接口中成員都有固定的修飾符:
- 常量:public static final
- 方法:public abstract
- 注:接口中的常量可以不寫 public static final,方法可以不寫 public abstract,編譯時會自動添加這些修飾符,這是 Java 中接口固定的修飾符,為了方便閱讀,一般都會寫上。
2. 特點
接口是程序功能的擴展。
接口是對外暴露的規則。
接口的出現降低了耦合性。
接口可以用來多實現,對于 Java 不支持多繼承的缺陷而做的轉換,Java 支持多實現。
類與接口之間是實現關系,類只能繼承一個類,但同時可以實現多個接口。
-
接口與接口之間可以有繼承關系,而且接口與接口之間支持多繼承。
注: 1. 接口不可以創建對象,因為接口有抽象方法需要子類實現(implements),子類需要全部重寫接口中的抽象方法后,子類才能實例化,否則該子類也會是抽象類。 2. 實現多個接口時,接口中不允許有返回類型不同的同名抽象函數,如果有這樣的情況時,子類實現將無法重寫接口的抽象方法。
3. 接口與抽象類
相同點:都是不斷向上抽取出來的抽象概念。
-
區別:
- 接口是實現,是 "like a" 關系;
- 抽象類是繼承,是 "is a" 關系。
- 接口中的常量和方法都是 public 修飾的權限;
- 抽象類中可以有私有變量或方法。
- 接口體現的是實現關系,可以多實現,接口與接口之間可以有繼承關系;
- 抽象類體現的是繼承關系,只能單繼承。
- 接口中所有方法都是抽象方法,接口中的成員都是有固定的修飾符;
- 抽象類中可以定義非抽象方法,提供給子類直接使用。
-
例如: