本篇博文講解的知識點比較實用,但是,相關知識點太多,所以本人將內容分為上下兩冊, 那麼,本人就不多廢話,直接進入主題進行講解了! 說到“繼承”,大家可能都會想到我們日常中對於這個詞的定義:將先人的 物品 或 意志 傳承給後人,而後人也可以“擇優繼承”,併在先人的基礎上產生 新的物品 或 新的意志。 ...
本篇博文講解的知識點比較實用,但是,相關知識點太多,所以本人將內容分為上下兩冊,
那麼,本人就不多廢話,直接進入主題進行講解了!
說到“繼承”,大家可能都會想到我們日常中對於這個詞的定義:將先人的 物品 或 意志 傳承給後人,而後人也可以“擇優繼承”,併在先人的基礎上產生 新的物品 或 新的意志。
上面這一段話,並不是為了瞎扯才寫出來的,上述的思想就是本人對於JAVA中的“繼承”的一種通俗的理解:
將父類的 成員 或 方法 傳承給 子類 , 而子類也可以選擇自己聲明一個同名的成員,或者 一個同名、同返回值、同參數的方法,併在父類的基礎上 定義 新的成員 或 新的方法 。
通過這樣描述,可能大家會對於繼承的優點就有了基本的認識。
那麼,現在,本人來總結一下 繼承的優點:
繼承的優點:
- 提高了代碼的復用性
- 提高了代碼的維護性
- 讓類與類之間產生了關係,是多態的前提
在這裡,本人還要提出的一點是:
Object類 是 所有類的基類(即 父類)
這樣一來,想必同學們對於這個知識點就有了大致的認識了,那麼,現在本人來編寫一段代碼來實現一下上述的思想:
首先,先在com.mec.about_inheritance.classes包下,來編寫一個 Parent.java 文件:
package com.mec.about_inheritance.classes;
public class Parent {
public int parentPublicMember;
private int parentPrivateMember;
protected int parentProtectedMember;
int parentNoneMember;
public Parent() {
parentPublicMember = 1;
parentPrivateMember = 2;
parentProtectedMember = 3;
System.out.println("Parent 無參構造方法");
}
public int parentPublicMethod() {
parentPrivateMethod();
System.out.println("執行Parent 類的 public 構造方法!");
return parentPrivateMember;
}
private void parentPrivateMethod() {
System.out.println("執行Parent 類的 private 構造方法!");
}
protected void parentProtectedMethod() {
System.out.println("執行Parent 類的 protected 構造方法!");
}
void parentNoneMethod() {
System.out.println("執行Parent 類的 無修飾 構造方法!");
}
}
現在,我們在本包(com.mec.about_inheritance.classes)下,來編寫它的子類——Child.java :
package com.mec.about_inheritance.classes;
public class Child extends Parent {
public Child() {
this. //這裡的代碼我們還沒敲完就能看到下圖現象:
}
}
我們能夠觀察到:它的父類的所有 無修飾 和 用protected、public修飾詞修飾的成員 和 方法,在本類中可以調用!
那麼,現在我們創建一個新的包com.mec.about_inheritance.test,在這個包下建立 Parent類 的 包外子類 Son類:
package com.mec.about_inheritance.test;
import com.mec.about_inheritance.classes.Parent;
public class Son extends Parent {
public Son() {
this. //這裡的代碼我們還沒敲完就能看到下圖現象:
}
}
我們能夠觀察到:它的父類的所有 用protected、public修飾詞修飾的成員 和 方法,在本類中可以調用!
那麼,現在我們創建一個新的包com.mec.about_inheritance.test,在這個包下建立 Parent類 的 包外非子類 Demo類:
package com.mec.about_inheritance.demo;
import com.mec.about_inheritance.classes.Child;
import com.mec.about_inheritance.classes.Parent;
import com.mec.about_inheritance.test.Son;
public class Demo {
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
Son son = new Son();
parent. //這裡的代碼我們還沒敲完就能看到下圖現象:
}
}
我們能夠觀察到:它調用的類的所有 用public修飾詞修飾的成員 和 方法,在本類中可以調用!
講到這裡,相信好多同學都已經懵了,畢竟本人也是從學習這個知識點的時期過來的,為了方便同學們對比這幾種的區別,本人現在將其總結羅列到一張表中:
許可權修飾符 總結:
修飾符 | 繼承關係 | 繼承關係 | 非派生類引用關係 | 非派生類引用關係 |
---|---|---|---|---|
適用範圍 | 包內子類 | 包外子類 | 包內其他類 | 包外其他類 |
public | 能 | 能 | 能 | 能 |
private | 否 | 否 | 否 | 否 |
protected | 能 | 能 | 能 | 否 |
default (或 無修飾) | 能 | 否 | 能 | 否 |
那麼,本人現在來介紹下,這些 許可權修飾符 的一般使用標準吧:
1.凡是打算為子類繼承的成員和方法,用 protected 修飾;
2.不打算被 包外的類 引用的 成員 和 方法 ,不用寫任何 許可權修飾符 。
我們之前說過,在我們構建一個比較大的JAVA工程時,一般都會用到 “構造方法”。
那麼,現在,本人來講解一下 繼承關係 中的 構造方法 :
我們還是通過代碼的運行結果來總結結論:
首先,在 com.mec.about_inheritance.constructor 包下建立 Grandfather 類:
package com.mec.about_inheritance.constructor;
public class Grandfather {
public Grandfather() {
System.out.println("執行爺爺構造方法!");
}
}
其次,我們在本包( com.mec.about_inheritance.constructor )下建立Parent 類:
package com.mec.about_inheritance.constructor;
public class Parent extends Grandfather {
public Parent() {
System.out.println("執行爸爸構造方法!");
}
}
然後,我們在本包( com.mec.about_inheritance.constructor )下建立Child 類:
package com.mec.about_inheritance.constructor;
public class Child extends Parent{
public Child() {
System.out.println("執行孩子構造方法!");
}
}
最後,我們建立一個新的包 com.mec.about_inheritance.constructor.test ,併在這個包下建立 Test類:
package com.mec.about_inheritance.constructor.test;
import com.mec.about_inheritance.constructor.Child;
public class Test {
public static void main(String[] args) {
new Child();
}
}
然後,我們來觀察下運行結果:
由此,我們可以看出,構造方法 的執行順序:
有當前類開始,根據繼承關係,追溯到祖先類,再從上往下執行構造方法!
但是,本人在之前的博文中說過,若一個類沒有定義無參構造方法,則JVM會預設執行一個無參構造方法。但是,在繼承這裡,正是由於這個原因,會出現一些錯誤,如下:
我們現在對 Grandfather類 進行如下改變:
package com.mec.about_inheritance.constructor;
public class Grandfather {
private int one;
private int two;
public Grandfather(int one, int two) {
this.one = one;
this.two = two;
System.out.println("執行爺爺構造方法!");
}
public int getOne() {
return one;
}
public void setOne(int one) {
this.one = one;
}
public int getTwo() {
return two;
}
public void setTwo(int two) {
this.two = two;
}
}
但是,就在這時,我們能夠發現,Parent類那裡竟然出現了錯誤:
錯誤提示說:父類Parent 的無參構造方法未定義,Parent類 無參構造方法必須執行另一種 父類 的構造方法。
簡單來講,就是說:因為Grandfather 類沒有無參構造方法。要 Parent 執行 另一種 父類構造方法。
其實,Grandfather 類並不是沒有構造方法,只是沒有無參構造方法!
所以,這裡執行 Grandfather 類的雙參構造方法!
現在,本人對 Parent類 做如下改變:
package com.mec.about_inheritance.constructor;
public class Parent extends Grandfather {
public Parent() {
super(0, 0);
System.out.println("執行爸爸構造方法!");
}
}
可以看到,現在沒有問題了!
由上面的代碼展示,我們可以看出繼承有如下特點:
繼承的特點:
- Java只支持單繼承,不支持多繼承(即 一個類只能擁有一個父類)
- Java支持 多層繼承(繼承體系)
但是,雖然這樣很方便,繼承也是存在著條件的:
- 子類只能繼承父類所有非私有的成員(成員方法和成員變數)
- 子類不能繼承父類的構造方法,但是可以通過super(待會兒講)關鍵字去訪問父類構造方法
- 不要為了 部分功能 而去 繼承
那麼,在本篇博文的末尾,本人要提出的一點是:我們雖然可以用“繼承”提高代碼的復用性,
但是,“繼承”同樣存在很大的弊端:
繼承的弊端: 使得 類的耦合性增強
這違背了我們的開發原則之一的 —— 高內聚,低耦合
(所謂“耦合”—— 類與類的關係
所謂 “內聚”—— 自己完成某件事情的能力)
相信看到這的同學們,一定對於super(0, 0) 這一行代碼十分好奇吧,那麼,請觀看本人的下半篇博文——《詳解 繼承(下)—— super關鍵字 與 多態》