1. 程式人生 > >super關鍵字和繼承中的潛規則

super關鍵字和繼承中的潛規則

java零基礎入門-面向物件篇(九)  繼承的規則

關於繼承的規矩很多,再加上初學者一般不會有太深的理解,所以學起來磕磕絆絆,繞來繞去,就差死記硬背了,我一直認為死記硬背的學習方法簡直就是個災難。

學習知識應該從原理開始理解,這樣就可以避免死記硬背的學習方式,我們這一章就當做一個學習方法的例子來講解,看看我們在學習過程中如何通過理解代替死記硬背

首先來看一個莫名其妙出場率很高的題目,過載和重寫。

過載和重寫

方法的過載,是在同一個類中,名稱相同,引數不同的方法。而重寫則是子類繼承父類以後,在子類中寫了一個和父類方法同名的方法。

我們繼續用上一章中的vip繼承來解釋這個概念。

過載與重寫

首先我們的普通玩家,可以有幾種購物的方法,可以單獨買一把大寶劍,也可以大寶劍和寵物一起買。而子類VIP1玩家繼承了父類普通玩家,但是VIP購物是可以打折的,所以VIP重寫了一個購物方法,因為他可以打折。只要我們稍微理解一下概念,就不會將過載和重寫的概念混淆,所以這個問題的出場率確實很莫名其妙。

super 關鍵字

當子類對父類的方法進行重寫以後,父類的方法就不可見了,也可以說是被覆蓋了。比如上面的例子,一旦你成為了VIP,那麼你買買買的時候,肯定是打折的,因為你不是普通玩家了,你無法呼叫普通玩家的方法。

無法呼叫父類中被覆蓋的方法

 

但是,天下沒有免費的午餐,也沒有免費的永久VIP,VIP可是有時間限制的,當你的VIP到期了,不好意思,要麼請繼續充錢當VIP,要麼回到普通玩家。現在我們在VIP的類中加一個到期時間,如果VIP到期,當他買買買的時候,呼叫的是普通玩家未打折的方法。

我們要在VIP中呼叫普通玩家的方法,上面不是說被覆蓋了不可見麼?其實我們是可以在子類中通過super關鍵字來呼叫父類被覆蓋的方法的。

 

super關鍵字呼叫

 

super和this

看了上面的例子,是不是聯想到我們曾經學過的this,他們確實有點像,但是也有區別。先來看看相似之處。

相似

1.沒有重名的時候,都會隱身,當有重名的時候必須現身。引數與成員變數重名,使用this,父類成員變數與子類成員變數重名,使用super。

 

1

2.他們都可以呼叫構造器。this呼叫自己類中的構造器,而super可以呼叫父類中的構造器。

super除了呼叫被子類重寫後被隱藏的成員變數和方法,還有一個重要的作用就是呼叫父類構造器。

子類構造時,會呼叫父類構造器,使用super則指定呼叫哪一個父類的構造器,如果不使用則預設呼叫父類的無參構造器。在時間順序上,先呼叫父類構造器,再呼叫子類構造器,如果直接父類還有父類,那麼再優先呼叫其父類的構造器,依次往上。

和this一樣,第一行只能出現this或者super之一,要麼呼叫自己的構造器,要麼呼叫父類構造器。來看看VIP對構造器的解釋

 

2

 

這裡有個概念要確定一下,構造器用來創造物件,但是這裡呼叫父類構造器並不是建立父類的物件,而是子類在建立物件的過程中,“借用” 父類構造器建立子類的物件。這個概念請不要混淆。

區別

this指代一個物件,哪個物件在呼叫方法,this就是哪個物件。而super不能指代一個物件,因為當子類被例項化的時候,並沒有建立父類的物件,所以super不能理解為父類的物件。

在建立子類物件的時候,並沒有建立父類物件,但是由於子類繼承了父類,記憶體中不但會劃分子類的變數空間,也會將子類的所有父類的成員變數也劃分記憶體空間,所以可以使用super去訪問他們。

 

直接列印super會報錯

允許重寫和阻止重寫

前面說封裝的時候,有一個修飾符叫protected,他是專門給子類用來重寫的時候定義的。因為父類定義private的時候,無論是變數還是方法,子類都是不可見的。所以當我們有個方法是專門給子類去重寫而又不希望被其他類發現的時候,我們可以定義為protected方法。

還有種情況是我們不希望子類重寫父類。比如我們普通玩家打怪的時候,一不小心怪沒打死,自己掛了。這時候會有系統懲罰的,比如掉經驗掉金幣,就算使用者是VIP,我也不希望他們改變這個機制,為什麼?因為你是VIP你打怪還能死,說明啥?要麼太傻,要麼是衝的錢還不夠!所以這個死亡掉經驗掉金幣的方法,不論是普通玩家不論是什麼等級的VIP,都不能改變。如何實現?

final 關鍵字,有一個用法就是阻止重寫。final這個關鍵字就好像一把鎖,加在誰面前,誰就不能再改了。加在變數前面,這個變數就變成常量了,不能再賦值了,加在方法前面,子類統統不能改。

 

阻止重寫

我們在開發軟體的過程中,會是一個多人配合團體合作的過程。所以當我們設計類,方法的時候,一定要考慮清楚,你可以很直觀的寫一個protected修飾符,告訴別的組員,我這個方法你可以寫個子類隨便改,也可以寫一個final告訴其他人我這個方法是不能改的。這樣不但可以節省溝通成本,還可以降低方法濫用造成的錯誤。

為什麼只能有一個直接父類?

我們可以回頭看看前面的定義,為什麼java中只允許有一個直接的父類?

學了super,我們知道super可以呼叫父類的屬性和方法,假如我們可以定義多個直接父類,那麼我們的super在呼叫的時候就不知道到底呼叫哪個直接父類了。

 

只能有一個直接父類

有沒有理解的更深點?

最後,來簡單聊一下所有物件的祖宗,java.lang.Object。這個Object 是所有類的父類,不管你的類結構是什麼樣,他永遠站在最頂端。有了它,你的類一生下來,就具有了一部分的方法,可以直接使用,具體的我會在講解java的包結構的時候為大傢俱體介紹,這裡先混個眼熟。