淺析Java三大特性封裝、繼承、多態,及作業分析
- 2020 年 5 月 2 日
- 筆記
前言
本次部落格銜接上次部落格,作為這一階段Java學習的分析。上一篇部落格著重介紹了Java的OO編程思維,面向對象與面向過程的區別。本篇部落格重心在Java的三大技術特性,附帶作業分析。
Java三大特性
封裝
在面向對象程式設計方法中,封裝是指一種將抽象性函式介面的實現細節部分包裝、隱藏起來的方法。
它將類的某些資訊隱藏在類的內部,不允許外部程式訪問,而是通過該類提供的方法來實現對隱藏資訊的操作和訪問。
實現封裝的方式:使用訪問控制符
- private 在當前類中可訪問
- default 在當前包內和訪問
- protected 在當前類和它派生的類中可訪問
- public 公眾的訪問許可權,誰都能訪問
還有伴隨著出現的還有getter和setter方法。(因知識面的原因,相關的package和import先不講解)
我們最常用的就是private,在繼承中,我們繼承的也是父類的非private的屬性和方法。封裝遵循了「封閉原則」,禁止外部直接訪問內部資訊。
封裝可以被認為是一個保護屏障,防止該類的程式碼和數據被外部類定義的程式碼隨機訪問。要訪問該類的程式碼和數據,必須通過嚴格的介面控制。適當的封裝可以讓程式碼更容易理解與維護,也加強了程式碼的安全性。
封裝的優點:
1. 良好的封裝能夠減少耦合。
2. 類內部的結構可以自由修改。
3. 可以對成員變數進行更精確的控制。
4. 隱藏資訊,實現細節。
繼承
繼承是類之間的一種關係,子類擁有父類非private的所有屬性和方法,從而實現了程式碼的復用。繼承是面向對象編程技術的基石,它允許了創建分等級層次的類。
我們為什麼要用繼承?
舉個例子:
我們擁有多個卡片,現在需要輸出每個卡片的形狀,那麼沒有繼承之前我們可能是每一個卡片類之中書寫System.out.println(「這張卡片的形狀是XXX」);然而我們可以繼承一個Shape類,Shape類中寫show(){ System.out.println(「這張卡片的形狀是」+name);}這樣程式碼的臃腫性就減少了,而且後期維護性較高。
程式碼示例[1]
開發動物類其中動物分別為企鵝以及老鼠,要求如下:
企鵝:屬性(姓名,id),方法(吃,睡,自我介紹)
老鼠:屬性(姓名,id),方法(吃,睡,自我介紹)
1 public class Penguin { 2 private String name; 3 private int id; 4 public Penguin(String myName, int myid) { 5 name = myName; 6 id = myid; 7 } 8 public void eat(){ 9 System.out.println(name+"正在吃"); 10 } 11 public void sleep(){ 12 System.out.println(name+"正在睡"); 13 } 14 public void introduction() { 15 System.out.println("大家好!我是" + id + "號" + name + "."); 16 } 17 }
1 public class Mouse { 2 private String name; 3 private int id; 4 public Mouse(String myName, int myid) { 5 name = myName; 6 id = myid; 7 } 8 public void eat(){ 9 System.out.println(name+"正在吃"); 10 } 11 public void sleep(){ 12 System.out.println(name+"正在睡"); 13 } 14 public void introduction() { 15 System.out.println("大家好!我是" + id + "號" + name + "."); 16 } 17 }
兩行程式碼對比可以看出程式碼重複已經出現,使得程式碼臃腫且後期維護性較低,使用繼承就能從根本上解決問題。提取二者的重複部分建立一個公共父類
1 public class Animal { 2 private String name; 3 private int id; 4 public Animal(String myName, int myid) { 5 name = myName; 6 id = myid; 7 } 8 public void eat(){ 9 System.out.println(name+"正在吃"); 10 } 11 public void sleep(){ 12 System.out.println(name+"正在睡"); 13 } 14 public void introduction() { 15 System.out.println("大家好!我是" + id + "號" + name + "."); 16 } 17 }
1 public class Penguin extends Animal { 2 public Penguin(String myName, int myid) { 3 super(myName, myid); 4 } 5 }
1 public class Mouse extends Animal { 2 public Mouse(String myName, int myid) { 3 super(myName, myid); 4 } 5 }
公共父類Animal擁有企鵝和老鼠類的相同屬性和方法,當企鵝和老鼠類繼承公共父類之後,子類也就不會再出現重複程式碼,且程式碼的臃腫性降低,可維護性升高。
我們也可以重寫重寫父類的方法,及命名與父類同名的成員變數,增加程式碼的靈活度。我們重寫的內容會覆蓋掉父類的內容,如果同時需要父類和子類的內容,我們可以使用super 與 this 關鍵字。而final關鍵字聲明類意義著不能繼承,即最終類;或用於修飾方法,不能被重寫。
super關鍵字:我們可以通過super關鍵字來實現對父類成員的訪問,用來引用當前對象的父類。
this關鍵字:指向自己的引用。
super和this程式碼示例[2]
1 class Animal { 2 void eat() { 3 System.out.println("animal : eat"); 4 } 5 } 6 7 class Dog extends Animal { 8 void eat() { 9 System.out.println("dog : eat"); 10 } 11 void eatTest() { 12 this.eat(); // this 調用自己的方法 13 super.eat(); // super 調用父類方法 14 } 15 } 16 17 public class Test { 18 public static void main(String[] args) { 19 Animal a = new Animal(); 20 a.eat(); 21 Dog d = new Dog(); 22 d.eatTest(); 23 } 24 }
輸出結果為:
animal : eat
dog : eat
animal : eat
如果我們想儘可能的隱藏程式碼,但是仍然允許子類的成員來訪問它們。這時候可以使用protected。(關於繼承許可權的問題可能會在後續的學習中再進行補充)
關於繼承(extends)和實現(implement)的區別
extends
1、類的繼承是單一繼承,也就是說,一個子類只能擁有一個父類,所以 extends 只能繼承一個類。
2、在繼承中可以定義屬性方法,變數,常量等…
Implement
1、Implement可以有多個介面,(介面跟介面之間採用逗號分隔)。
2、在介面中只能定義全局常量(static final),和空的方法體。
3、 某個介面被類實現時,在類中一定要實現介面中的抽象方法。
繼承類型[3]
多態
概念:多態是同一個行為具有多個不同表現形式或形態的能力。
Java實現多態的三個必要條件:繼承、重寫、向上轉型
1、繼承:在多態中必須存在有繼承關係的子類和父類。
2、重寫:子類對父類中某些方法進行重新定義,在調用這些方法時就會調用子類的方法。
3、向上轉型:在多態中需要將子類的引用賦給父類對象,只有這樣該引用才能夠具備技能調用父類的方法和子類的方法。
使用多態的好處之一是當調用方法時,先檢查父類中是否擁有該方法,如果沒有則編譯錯誤,如果有,再調用子類的同名方法。使類的對象可以進行通用化處理,同時增加了程式的延展性。
實現多態的方式
1、基於繼承實現的多態:
基於繼承實現的多態主要是重寫,子類的重寫。多個子類的同一方法的重寫可以表現出不同的行為。
2、基於介面實現的多態:
基於介面實現的多態主要是實現介面並覆蓋介面中同一方法的幾不同的類體現的。
繼承都是單繼承,只能為一組相關的類提供一致的服務介面。但是介面可以是多繼承多實現,它能夠利用一組相關或者不相關的介面進行組合與擴充,能夠對外提供一致的服務介面。所以它相對於繼承來說有更好的靈活性。
作業方面
這幾次作業知識迭代正變得更加符合Java的三大技術特性,不管是封裝性還是繼承性、多態性,這幾次作業所給的UML類圖也都能感覺到這些特性。
關於這幾次作業的問題,除了正則表達是以外就是關於ArrayList自定義類的的使用有所不理解。
例如ArrayList<Integer>list中能很簡單的理解Integer的意義並簡單的使用,但是遇到了自定義的ArrayList<Card> cardList限定範圍在自定義的<Card>類的範圍以內,就不知道如何是好,其實理解並使用是一件比較簡單事情,像integer類型的list.add(整型),整型是是整數類型的數字,而像Card類型的list.add(卡片),卡片是放入的卡片類的對象。
1 double radius = Main.input.nextDouble(); 2 Shape circle = new Circle(radius);3 Card card = new Card(circle); 4 cardList.add(card);
//簡單的程式碼示例不做過多解釋,理解使用
網路上還有更加詳細的Arraylist自定義類的教程,比我淺薄的表達要好的多,可以篩選並學習,當學會了Arraylist自己定義類,我感覺這兩次的作業的難點也算是攻克了。
關於時間
這幾次的作業花費時間最多的是水文測試的題目,因為涉及正則表達式,對於一個粗心的人來說,學習並使用正則表達式簡直就是噩夢。花費時間最短的就是最近的一次作業,原因也就是沒有新的知識的擴展,寫起程式碼來也算是比較暢通。
關於測試
良好的測試並獲取程式碼的資訊式寫好程式碼的必要條件,隨著程式碼長度及程式碼難度的增加測試的重要性也慢慢的體現了出來,現在沒有學會使用Debug的同學要開始加強學習了。
關於收穫
這一階段的收穫一個是正則表達式的使用,另一個就是Java三大技術特性封裝、繼承、多態的理解和使用。
關於課程建議
作業體量、難度方面沒有什麼建議,關於作業的建議就是更加詳細點對作業中新出現的知識點進行講解擴充,也可以給予相關的教程方便後續的複習。
參考文獻
[1][2][3]菜鳥教程//www.runoob.com/java/java-inheritance.html