500 likes | 702 Views
Managing Inheritance. Lecturer :楊昌樺. Outline. 存取控制( Access Control ) static 關鍵字 實體成員與類別成員 static 初值設定區塊 Your Turn 物件導向語言三大特性 封裝 ( Encapsulation) 繼承( Inheritance ) 同名異型( Polymorphism ) Overriding Overloading super 關鍵字 Java 物件祖先: Object 類別 Final Classes and Methods Your Turn.
E N D
Managing Inheritance Lecturer:楊昌樺
Outline • 存取控制(Access Control) • static 關鍵字 • 實體成員與類別成員 • static 初值設定區塊 • Your Turn • 物件導向語言三大特性 • 封裝 (Encapsulation) • 繼承(Inheritance) • 同名異型( Polymorphism ) • Overriding • Overloading • super 關鍵字 • Java 物件祖先:Object 類別 • Final Classes and Methods • Your Turn
存取控制(Access Control) • 控制存取的關鍵字 • public、protected、private • 置於類別或成員宣告之前 • 若沒有指定任何存取權限,表示此類別或成員僅供相同類別庫的其他類別使用,稱為 package access層級 • 將類別或成員設定為 package access 層級的好處是可使同在一個類別庫下的每個類別互相使用成員
存取控制(Access Control) • public • 任何類別皆可存取 • default • packetage access • protected • 允許宣告的類別、子類別與同一個套件中的類別使用 • private • 只有在類別內部可以存取 • 對於成員變數,通常設定為 private 權限,再透過 methods,如 get/set 來存取資料
存取控制(Access Control) • Class Access • 類別不可設定為 private 或 protected • 若為了避免他人任意使用 constructors 建立物件 • 可將 constructors 設定為 private • 另外提供 static 的 methods 建立物件、複製物件 • main() 必須由程式外部的程式碼來呼叫(Java 執行時期系統),所以 main() 必須為 public • 設計存取秘訣: • 設定適合但最嚴苛的存取等級。因此,盡量使用 private。 • 如此在修改成員變數內容時,只能透過 method。除非,在評估設為 public後會對於程式效能有顯著提升的情況。
Package與示範存取的範例 用eclipse功能 new->package, 建立Package “One” 在One裡面新增類別 “Alpha” Alpha類別只是一個單純的物件類別 在One裡面新增類別“DeltaOne” DeltaOne類別用同Package的Alpha類別建立物件 新增Package “Two” 新增類別“Delta Two” DeltaTwo類別用別Package的Alpha類別建立物件
存取控制(Access Control)範例 • Example: Alpha.java private int iamprivate = 1; int iampackage = 2; //package access protected int iamprotected = 3; public int iampublic = 4; private void privateMethod() { System.out.println("iamprivate Method"); } void packageMethod() { // default: package access System.out.println("iampackage Method"); } protected void protectedMethod() { System.out.println("iamprotected Method"); } public void publicMethod() { System.out.println("iampublic Method"); }
存取控制(Access Control)範例 • Example: DeltaOne.java package One; public class DeltaOne { public static void main(String[] args) { Alpha a = new Alpha(); //a.privateMethod(); //illegal a.packageMethod(); //legal a.protectedMethod(); //legal a.publicMethod(); //legal //System.out.println("iamprivate: “ + a.iamprivate); //illegal System.out.println("iampackage: “ + a.iampackage); //legal System.out.println("iamprotected: “ + a.iamprotected); //legal System.out.println("iampublic: “ + a.iampublic); //legal } }
存取控制(Access Control)範例 • Example: DeltaTwo.java package Two; import One.*; public class DeltaTwo { public static void main(String[] args) { Alpha alpha = new Alpha(); //alpha.privateMethod(); //illegal //alpha.packageMethod(); //illegal //alpha.protectedMethod(); //illegal alpha.publicMethod(); //legal //System.out.println("iamprivate: “ + alpha.iamprivate); //illegal //System.out.println("iampackage: “ + alpha.iampackage); //illegal //System.out.println("iamprotected: “ + alpha.iamprotected); //illegal System.out.println("iampublic: “ + alpha.iampublic); //legal } }
static 關鍵字 • 實體成員與類別成員 • 變數或 methods 若宣告為 static,則此變數或 methods 即為類別變數(class variables)或類別方法(class methods) • 宣告為 static 的變數或 methods 不屬於任何此類別的物件,乃此類別所有物件共同擁有 • 宣告 • static DataType VarName; • static ReturnTypeMethodName(Arg List) • 使用 • ClassName.VarName • ClassName.MethodName(Arg List)
static 關鍵字 • 使用時機 • 無論此類別擁有多少物件,這份資料只需要一份 • 某種方法在實行時,與個別的物件無關 • 即便是沒有任何物件被產生,依舊可以使用被宣告成 static 的變數與 methods;相反的,instance variables 與 methods 必須透過物件才能實施 • 在 static methods 裡,無法直接呼叫 instance methods 或直接使用 instance variables • 因為 instance variables 與 methods 必須透過物件才能實施
static 關鍵字 • 被用 static 宣告的類別方法和類別變數,意思上就像是其他程式語言中的全域函數(global functions)和全域變數(global variables),例如:C語言 • 因此,如果要很多宣告成 static 的方法或變數的話,必須要謹慎使用!
static 關鍵字 - 實體成員與類別成員 • Example: StaticDemo.java public class StaticDemo { public int instanceInteger = 0; public int instanceMethod() { return instanceInteger; } public static int classInteger = 0; public static int classMethod() { return classInteger; } public static void main(String[] args) { … } }
static 初值設定區塊 • class 變數或是實體變數,可以直接設定初值 public class BedAndBreakfast { public static final int MAX_CAPACITY = 10; //initialize to 10 private boolean full = false; //initialize to false } • 限制: • 不能用 if-else 來設定初值 • 設定初值時,不可以處理 exceptions • 若發生 exceptions,也無法做錯誤處理
static 初值設定區塊 • static 初值設定區塊 • Java 允許將 static 變數集合起來進行初始化動作 • 語法: • 因為 x 和 isOK 都是 class 變數,無法在建構元中設定初值,且利用 static 初設設定區塊可以處理 exceptions。 • class TestClass{ • static int x; static boolean isOK; • static{ • x = 100; //static int x; • isOK = false; // static isOK; • } • }
建構元(Constructors) • 修飾建構元的關鍵字 • private • 如果一個類別裡所有的建構元都是宣告成 private 的話,那這個類別應該會有 public 的類別方法(class method),讓其他類別建立此類別之物件 • protected • 只有該類別的 subclass,或是屬同一個 package 裡的類別,才可以使用此建構元 • public • 所有類別都可以使用此建構元 • 預設 • 只有同一個 package 裡的類別,才能使用此建構元
Your Turn • 整理上次寫的 Rectangle 類別 • 此類別必須完成下列要求 • 此類別不提供constructor 供外部存取(為 private) • 要提供三個 class methods 來建立 Rectangle 物件 • 第一個是使用預設長寬:長 8,寬 4(createRect) • 第二個是可以讓使用者自行指定(createRect) • 第三個複製矩形(cloneRect) • 顯示目前的長、寬之值(showLW) • 取得目前矩形之面積(getArea) • 畫矩形,由 * 構成邊長(drawRect)
Your Turn • Hint // 建構元 private Rectangle(){ … } // 另一個建構元 private Rectangle(int length, int width){ … } // 此建構元提供給 cloneObj 用,用以複製 private Rectangle(Rectangle obj){ … } // 提供一個可以製造長方形的 class method static Rectangle createRect() { … } // 提供一個可以製造且自行設定長方形的 class method static Rectangle createRect(int len, int width) { … } // 複製此長方形 static Rectangle cloneRect(Rectangle obj) { … } // 顯示現在的長、寬 void showLW() { … } // 取得現在的面積 double getArea(){ … } // 畫出此長方形 void drawRect(){ … }
物件導向三大特性 • 封裝 (Encapsulation) • 設計 Class,決定要將哪些屬性,方法,事件封入類別中的動作叫做封裝。 • 讓程式碼可以以Class為單位分類,並讓文件撰寫可以用物件導向模式撰寫 (e.g., class diagram)。 • 繼承 (Inheritance) • 設計 Class 時,先利用現存 Class 作為 “祖先”,再加以增加或修改功能的動作叫繼承。 • 讓程式碼可以輕易地重複使用,並形成樹狀結構之class diagram。 • 同名異型 (Polymorphism) • 呼叫相同的函式,卻會出現不同的行為的現象,稱為同名異型。分為 “overriding” 及 “overloading”。 • 擴充既有程式碼之功能。
屬性: 身高 體重 年齡 方法: 走路 跑步 事件: 被打 驚嚇 開心 物件導向三大特性 • 封裝 (Encapsulation) • 設計一個 Class 的屬性,方法,事件,稱為 “封裝” 一個類別。 人類
屬性: 身高 體重 年齡 方法: 走路 跑步 貝多芬 事件: 被打 驚嚇 開心 物件導向三大特性 • 繼承 (Inheritance) • 設計 Class 時,先利用現存 Class 作為 “祖先”, • 再加以增加或修改功能的動作叫繼承。 • 讓程式碼可以輕易地重複使用,並形成樹狀結構之class diagram 人類 = 165 = 80 = 45 音樂家 作曲 發表
屬性: 身高 體重 年齡 方法: 走路 跑步 事件: 被打 驚嚇 開心 物件導向三大特性 • 同名異型 (Polymorphism) • Overriding • 若繼承下來後,不滿意祖先定義的方法,子孫可以在繼承以後重新改寫,稱為 Overriding。 人類 人類.走路() { 約一分鐘三十步 } 音樂家 音樂家.走路() { 約一分鐘十步 } 作曲 同樣是呼叫 “走路”, 宣告成人類與音樂家 就是不一樣。 發表
屬性: 身高 體重 年齡 方法: 走路 跑步 事件: 被打 驚嚇 開心 物件導向三大特性 • 同名異型 (Polymorphism) • Overloading • 同一份函式,準備多種定義,以供各種場合呼叫,稱為Overloading。 人類 音樂家.作曲(“王先生”) 音樂家 作曲 作曲 (委託人) 自動判斷
封裝 (Encapsulation) • 將資料(屬性)與方法(行為)封裝在一個物件裡頭,物件裡頭的資料與方法被緊緊的綁在一起,並擁有資訊隱藏(Information hiding)的特性。 • Example: TimeDemo.java class Time { private int hour; private int minute; private int second; public Time() { … } public void setTime(int hh,int mm,int ss) { … } public String toString() { … }}
繼承(Inheritance) • 繼承概念圖
繼承(Inheritance) • 語法:class ClassName extends BaseClass • 例如:class Line extends GraphicsObject • Base Class(SuperClass):基底類別、父類別 • Derived Class(Subclass):衍生類別、子類別 • Java 理論上不支援多重繼承,也就是說,一個子類別只能有一個父類別。 • 子類別將會繼承到父類別中所有可以存取的成員,包括:變數以及方法 • 注意:建構元(constructor)無法被繼承 • Java 中每個物件的總祖先:Object 類別( java.lang.Object )
繼承(Inheritance) • 可繼承成員 • Superclass 中宣告為 public或 protected的成員。 • 如果 Subclass 與 Superclass 在同一個 package 中,會繼承未做任何存取控制宣告的成員。 • 不可繼承成員 • 如果 Subclass 與 Superclass 在不同 package,所有未宣告有效範圍的成員全部不繼承。(因為預設式 package access) • Superclass 中宣告成 private 的成員
繼承(Inheritance) • Example: Dog.java public class Dog { // 屬性 (Variables) private String name; private String color; private int age; // 建構元 (Constructor) public Dog(String name, String color, int age){ this.name = name; this.color = color; this.age = age; } // 方法 (Methods) public void bark() { … } public void handshake() { … } public void rollover(int theTimes) { … } … }
繼承(Inheritance) • Example: Pomer.java public class Pomer extends Dog { // 建構元 public Pomer(String name, String color, int age) { super(name, color, age); } // 新的方法 public void proud() { System.out.println("哼..."); } }
同名異型( Polymorphism ) • 覆蓋 Overriding • 若繼承下來後,不滿意祖先定義的方法,子孫可以在繼承以後重新改寫,稱為 Overriding。 • 可覆蓋成員 • 任何與 Superclass 同名的成員 • 必覆蓋成員 • Subclass 一定要覆蓋 superclass 中宣告為 abstract 的 methods,除非 subclass 本身也是 abstract 類別 • 不可覆蓋成員 • Subclass 不可覆蓋 superclass 的 final methods
同名異型( Polymorphism ) • 覆蓋 Overriding • 將 父類別 Dog 的 Handshake 方法 Override 掉 class Pomer extends Dog { // 建構元 public Pomer (String name, String color, String age) { super(name, color, age); } // 將父類別 Dog 中原有的 handshake() 方法 Override 掉 public void handshake() { System.out.println("你的手洗了嗎?"); } public void proud() { System.out.println(“哼..."); } }
同名異型( Polymorphism ) • 過載 Overloading • 同一份函式,準備多種定義,以供各種場合呼叫,稱為Overloading。 • 建構元也可以利用參數的不同,來達成 overloading
同名異型( Polymorphism ) • 建構元的 Overloading class Pomer extends Dog { // 具有 overloading 的建構元 public Pomer() { super(“GoodDog”, “Red”, 12); } public Pomer (String name, String color, String age) { super(name, color, age); } // override 父類別 Dog 中的 handshake() 方法 public void handshake() { System.out.println("你的手洗了嗎?"); } public void proud() { System.out.println(“哼..."); } }
同名異型( Polymorphism ) • 方法的 Overloading • class Pomer extends Dog { • // 建構元 • public Pomer (String name, String color, String age) { • super(name, color, age); • } • // 具有 overloading 的 rollover() • public void rollover() { • for (int i=1; i<=5; i++) • System.out.println("我滾 " + i + " 次"); • } • public void rollover(int thetimes) { • for (int i=1; i<=thetimes; i++)…
super 關鍵字 • this & super 關鍵字 • this:指的是目前的 class • super:指的是父類別 • 使用 super 來呼叫父類別中的方法 語法:super.methodName(argList); • super.Bark(); • super.Rollover(5); • 若子類別中沒有建構元(constructor),可單用 super 來呼叫父類別中的建構元 語法:super(argList);
Java 物件祖先:Object 類別 • Java 中的所有物件,全部繼承自 java.lang.Object • 只要程式師沒有以 extends 指定 繼承之物件,Java 會自動用 Object 作為所有物件的父物件。
Java 物件祖先:Object 類別 • 以下是 Object 中的方法,可能是您想 Overriding 的: • clone() • equals() • toString() • finalize() • 以下是 Object 中,宣告為 final 的方法,不可以 Overriding: • getClass() • hashCode() • notify() • notifyAll() • wait()
Java 物件祖先:Object 類別 • clone() • 原始宣告:protected Object clone() throws CloneNotSupportedException • 作用:複製一份物件本身,並傳回去。 • 要求: • 要讓類別成為可複製類別的最簡單方法:在類別宣告最後加上 implements Cloneable • Object 提供的 clone() 功能很適合,但有些類別必須要覆蓋 clone(),才能提供正確的複製功能
Java 物件祖先:Object 類別 • equals() • 原始宣告:public boolean equals(Object obj); • 作用:比較兩個物件的內含值是否相等。 • 要求:無 • hashCode() • 回傳的 int 數值,代表物件在 hash table 裡對應位置。 • 傳回物件在 “雜湊表” (Hash Table) 中的索引值。通常配合 java.util.Hashtable 使用
Java 物件祖先:Object 類別 • finalize() • 原始宣告:protected void finalize() throws Throwable • 作用:物件離開其有效範圍時,一定會被叫用的函式。用來清除本物件以 new 霸佔的記憶體。 • 系統會自動呼叫 finalize(),因此大部分的類別都不需要覆蓋 finalize() • 所以在 Java 中,要拋棄一個記憶體,只要: • ObjA = null; • ObjB = null;
Java 物件祖先:Object 類別 • toString() • 原始宣告:public String toString(); • 作用:傳回一個此物件的描述字串 • toString() 對除錯(debug)很有幫助 System.out.println(new Double(Math.PI).toString());
Java 物件祖先:Object 類別 • 改寫從Object物件繼承來的toString()方法 • Example: TimeDemo.java class Time { … public String toString() { return (hour+":"+(minute<10? "0" : "")+minute+ ":"+(second<10? "0" : "")+second); } }
Java 物件祖先:Object 類別 • getClass() • 原始宣告:public final Class getClass(); • 作用:可取得一個類別的所有資訊。包括類別名稱,父類別名稱,實作介面名稱,所有成員變數及成員函式,甚至於可以由取回的 class 資料個體化一個物件。 • 要求:不准覆寫 (Overriding) • 傳回值:傳回 java.lang.Class。傳回後,您就可以使用所有 java.lang.Class 的屬性與方法。
Final Classes and Methods • Final Classes • 定義 • 一個不准被別人繼承的類別稱為 final class • 宣告 語法:AccessLevel final class ClassName • 如:final class ColorPoint • 使用時機 • 安全性 • 駭客最常用來破壞系統的方式,建立某個類別的 subclass,然後將原來類別的主體置換成自己的主體。 • 當一個類別已經十分完美時
Final Classes and Methods • Final Classes final class A {//…}// The following class is illegal.class B extends A //錯誤!無法形成A的子類別{ //…}
Final Classes and Methods • Final Methods • 定義 • 一個不准被 subclass 覆寫(Overriding)的函式稱為 final method • 宣告 • 語法:final 傳回值型態 函式名稱 (參數, …); • 使用時機 • 當覆寫(Overriding)會出現問題時。
Final Classes and Methods • Final Methods class A { final void meth() { System.out.println("This is a final method."); }}class B extends A { void meth( ) //這裡開始會出現錯誤!不能覆蓋。 { System.out.println("Illegal!"); }}
實例講解 • 程式:InheritanceDemo.java • 類別成員(Class Method) • 繼承(Inheritance) • Overriding • Overloading • super
Your Turn • 試用 Dog 類別產生一個 如GoldenRetriever (黃金獵犬)類別 • 具有兩個建構元(Overloading) • GoldRetriever() 預設:如流浪狗、金色、5 歲不傳任何參數時、呼叫overloading的建構元呼叫方式如this(“流浪狗”,“金色”,5); • GoldRetriever(String theName, String theColor, int theAge)初始化其實跟Dog父類別一樣, 呼叫方式如 super(theName,theColor,theAge); • 多一個方法 smile(),如印出 “^_^” • Override 原本 Dog 類別中的 bark() 方法,如印出 “嘻嘻~” • Override Object 中的 toString(),如印出“我是一隻可愛的黃金獵犬!”