JAVA基礎再回首(六)——父與子的繼承、super關鍵字、方法重寫、方法重載
不墨迹,才是時間管理的最大利器,學無止境。
繼承
首先我們來學習繼承的概述
- 多個類中存在相同屬性和行為時,将這些内容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行為,隻要繼承那個類即可。
- 通過extends關鍵字可以實作類與類的繼承
- 格式:class 子類名 extends 父類名 {}
- 單獨的這個類稱為父類,基類或者超類;這多個類可以稱為子類或者派生類。
- 有了繼承以後,我們定義一個類的時候,可以在一個已經存在的類的基礎上,還可以定義自己的新成員。
以前我們沒有學習繼承之前,是這樣定義一個類和類中的方法的。
//使用繼承前
class Student {
public void eat() {
System.out.println("吃飯");
}
public void sleep() {
System.out.println("睡覺");
}
}
class Teacher {
public void eat() {
System.out.println("吃飯");
}
public void sleep() {
System.out.println("睡覺");
}
}
通過觀察我們可以學生類和老師類他們都有共同的方法就是吃和睡,既然老司機已經帶我們上路了,那麼我們就可以改進上面的代碼,将相同的成員抽取到一個類中,争取早日成為一名老司機。
//使用繼承後
//首先我們定義一個人類,因為老師、學生都屬于人,都要吃飯和睡覺
class Person {
public void eat() {
System.out.println("吃飯");
}
public void sleep() {
System.out.println("睡覺");
}
}
class Student extends Person {}
class Teacher extends Person {}
public class ExtendsDemo {
public static void main(String[] args) {
Student s = new Student();
s.eat();
s.sleep();
System.out.println("-------------");
Teacher t = new Teacher();
t.eat();
t.sleep();
}
}
作為小司機可以看到使用繼承前後的輸出結果相同
運用了繼承後,我們可以看到繼承的好處也就是優點。
- 提高了代碼的複用性
- 多個類相同的成員可以放到同一個類中
- 提高了代碼的維護性
- 如果功能的代碼需要修改,修改一處即可
- 讓類與類之間産生了關系,是多态的前提
當然運用了繼承後,他也是存在弊端的
- 類的耦合性很強
設計原則: 高内聚低耦合。
簡單的了解:
内聚就是自己完成某件事情的能力。
耦合就是類與類之間的關系。
我們在設計的時候原則是:自己能完成的就不麻煩别人,這樣将來别人産生了修改,就對我的影響較小。
由此可見:在開發中使用繼承其實是在使用一把雙刃劍。今天我們還是以繼承的好處來使用,因為繼承還有很多其他的特性。
我們了解了繼承的概述,繼續了解Java中繼承的特點
- Java隻支援單繼承,不支援多繼承。
- 一個類隻能有一個父類,不可以有多個父類。
- class SubDemo extends Demo{} //ok
- class SubDemo extends Demo1,Demo2…//error
- Java支援多層繼承(繼承體系)
- class A{}
- class B extends A{}
- class C extends B{}
我們一起寫個小Demo驗證繼承的特點!
//Java隻支援單繼承,不支援多繼承。
class Father {}
class Mother {}
class Son exnteds Father {} //正确的
class Son extends Father,Mother {} // 錯誤的
//Java支援多層繼承
class GrandFather {
public void show() {
System.out.println("我是爺爺");
}
}
class Father extends GrandFather {
public void method(){
System.out.println("我是老子");
}
}
class Son extends Father {}
class ExtendsDemo2 {
public static void main(String[] args) {
Son s = new Son();
s.method(); //使用父親的
s.show(); //使用爺爺的
}
}
那麼,在Java中繼承的注意事項有哪些呢?
- 子類隻能繼承父類所有非私有的成員(成員方法和成員變量)
- 其實這也展現了繼承的另一個弊端:打破了封裝性
- 子類不能繼承父類的構造方法,但是可以通過super關鍵字去通路父類構造方法。
- 不要為了部分功能而去繼承
- 我們到底在什麼時候使用繼承呢?
- 繼承中類之間展現的是:”is a”的關系。
- 舉例:水果和蘋果,蘋果是一種水果。
- 學生和人,學生是人的一種。
- 是以我們總結采用假設法。如果有兩個類A,B。隻有他們符合A是B的一種,或者B是A的一種,就可以考慮使用繼承。
class Father {
private int num = ;
public int num2 = ;
//私有方法,子類不能繼承
private void method() {
System.out.println(num);
System.out.println(num2);
}
public void show() {
System.out.println(num);
System.out.println(num2);
}
}
class Son extends Father {
public void function() {
//num可以在Father中通路private
//System.out.println(num); //子類不能繼承父類的私有成員變量
System.out.println(num2);
}
}
public class ExtendsDemo {
public static void main(String[] args) {
// 建立對象
Son s = new Son();
//s.method(); //子類不能繼承父類的私有成員方法
s.show();
s.function();
}
}
輸出結果:
10
20
20
繼承中成員變量的關系
- A:子類中的成員變量和父類中的成員變量名稱不一樣,這個太簡單。
- B:子類中的成員變量和父類中的成員變量名稱一樣,這個怎麼玩呢?
- 結論在子類方法中通路一個變量的查找順序:
- a:在子類方法的局部範圍找,有就使用
- b:在子類的成員範圍找,有就使用
- c:在父類的成員範圍找,有就使用
- d:如果還找不到,就報錯。
- 結論在子類方法中通路一個變量的查找順序:
class Father {
public int num = ;
public void method() {
int num = ;
}
}
class Son extends Father {
public int num2 = ;
public int num = ;
public void show() {
int num = ;
System.out.println(num);
System.out.println(num2);
// 找不到符号,報錯
//System.out.println(num3);
}
}
public class ExtendsDemo {
public static void main(String[] args) {
// 建立對象
Son s = new Son();
s.show();
}
}
輸出結果:記住上面的結論,到哪裡都不會出錯的
下面來學習super關鍵字
super關鍵字
- super的用法和this很像
- this代表本類對應的引用。
- super代表父類存儲空間的辨別(可以了解為父類引用,可以操作父類的成員)
- 用法(this和super均可如下使用)
- 通路成員變量
- this.成員變量 調用本類的成員變量
- super.成員變量 調用父類的成員變量
- 通路成員變量
- 通路構造方法
- this(…) 調用本類的構造方法
- super(…) 調用父類的構造方法
- 通路成員方法
- this.成員方法() 調用本類的成員方法
- super.成員方法() 調用父類的成員方法
class Father {
public int num = ;
}
class Son extends Father {
public int num = ;
public void show() {
int num = ;
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
public class ExtendsDemo{
public static void main(String[] args) {
Son s = new Son();
s.show();
}
}
輸出結果:
繼承中構造方法的關系
- 子類中所有的構造方法預設都會通路父類中空參數的構造方法
- 因為子類會繼承父類中的資料,可能還會使用父類的資料。是以,子類初始化之前,一定要先完成父類資料的初始化。
- 注意:子類每一個構造方法的第一條語句預設都是:super();
class Father {
int age;
public Father() {
System.out.println("Father的無參構造方法");
}
public Father(String name) {
System.out.println("Father的帶參構造方法");
}
}
class Son extends Father {
public Son() {
//super();
System.out.println("Son的無參構造方法");
}
public Son(String name) {
//super();
System.out.println("Son的帶參構造方法");
}
}
public class ExtendsDemo {
public static void main(String[] args) {
//建立對象
Son s = new Son();
System.out.println("------------");
Son s2 = new Son("寶寶");
}
}
輸出結果:
如果父類沒有無參構造方法,那麼子類的構造方法會出現什麼現象呢?我注釋了上面例子中父類的無參構造,然後項目報錯了,那麼我們怎麼解決呢?
- 在父類中加一個無參構造方法
- 通過使用super關鍵字去顯示的調用父類的帶參構造方法
- 子類通過this去調用本類的其他構造方法
- (子類中一定要有一個去通路了父類的構造方法,否則父類資料就沒有初始化。)
- 注意事項:
- this(…)或者super(…)必須出現在第一條語句上。
- 如果不是放在第一條語句上,就可能對父類的資料進行了多次初始化,是以必須放在第一條語句上。
上面說了這麼多,不知道你是否了解了,我們通過Demo再來學習
class Father {
int age;
/*public Father() {
System.out.println("Father的無參構造方法");
}*/
public Father(String name) {
System.out.println("Father的帶參構造方法");
}
}
class Son extends Father {
public Son() {
super("111");
System.out.println("Son的無參構造方法");
// super("111");
}
public Son(String name) {
// super("222");
this();
System.out.println("Son的帶參構造方法");
}
}
public class ExtendsDemo {
public static void main(String[] args) {
//建立對象
Son s = new Son();
System.out.println("------------");
Son s2 = new Son("寶寶");
}
}
輸出結果:不知道你通過上面的概念是否能觀察出結果呢,不能的話就要去多想多練多了解
繼承中成員方法的關系:
- A:子類中的方法和父類中的方法聲明不一樣,這個太簡單。
- B:子類中的方法和父類中的方法聲明一樣,這個該怎麼玩呢?
- 通過子類對象調用方法:
- a:先找子類中,看有沒有這個方法,有就使用,沒有就在父類中找
- b:再看父類中,有沒有這個方法,有就使用
- c:如果沒有就報錯。
- 通過子類對象調用方法:
方法重寫、方法重載
- 方法重寫概述
- 子類中出現了和父類中一模一樣的方法聲明,也被稱為方法覆寫,方法複寫。
- 方法重載概述
- 本類中出現的方法名一樣,參數清單不同的方法。與傳回值無關。
- 使用特點:
- 如果方法名不同,就調用對應的方法
- 如果方法名相同,最終使用的是子類自己的
- 方法重寫的應用:
- 當子類需要父類的功能,而功能主體子類有自己特有内容時,可以重寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的内容。
class Phone {
public void call(String name) {
System.out.println("給"+name+"打電話");
}
}
class NewPhone extends Phone {
public void call(String name) {
super.call(name);
System.out.println("打完電話了,我要聽首歌");
}
}
public class ExtendsDemo {
public static void main(String[] args) {
NewPhone np = new NewPhone();
np.call("老闆");
}
}
輸出結果: 上面的Demo中,手機打電話功能,是手機本身就具備的最基本的功能。是以,新手機是不用在提供這個功能的。由于它繼承了手機類,是以,我們就直接使用父類的功能即可。通過super關鍵字調用
- 方法重寫的注意事項
- A:父類中私有方法不能被重寫(因為父類私有方法子類根本就無法繼承)
- B:子類重寫父類方法時(通路權限不能更低,最好就一緻)
- C:父類靜态方法,子類也必須通過靜态方法進行重寫
- 子類重寫父類方法的時候,最好聲明一模一樣。
我們一起來做兩個經典例題
- 方法重寫(Override)和方法重載(Overload)的差別?方法重載能改變傳回值類型嗎?
方法重寫:在子類中,出現和父類中一模一樣的方法聲明的現象。
方法重載:同一個類中,出現的方法名相同,參數清單不同的現象。
方法重載能改變傳回值類型,因為它和傳回值類型無關。
- this關鍵字和super關鍵字分别代表什麼?以及他們各自的使用場景和作用。
this:代表目前類的對象引用
super:代表父類存儲空間的辨別。(可以了解為父類的引用,通過這個東西可以通路父類的成員)
場景:
成員變量:this.成員變量——super.成員變量
構造方法:this(…)——super(…)
成員方法:this.成員方法——super.成員方法
好了,今天我們學了這麼多,要好好消化一下,做到學以緻用。最後送大家一句話。
不管有多苦,千萬要記住:苦難是我們人生路上不可缺少的經曆,隻有活着,才有幸福的可能!