Chap 9 巢狀類別 多形與套件 9-1 巢狀類別 9-2 匿名內層類別 9-3 多形的基礎 9-4 多形的實作 9-5 套件
9-1 巢狀類別 9-1-1 巢狀類別 9-1-2 內層類別的使用
9-1-1 巢狀類別 - 說明 巢狀類別是在類別中擁有其他類別的宣告, 在外面的類別稱為 外層類別 (Enclosing Class); 內層的成員類別稱為 內層類別 (Inner Classes) 巢狀類別強調類別之間的關聯性, 內層類別一定需要外層類別, 如果外層類別的物件不存在, 內層類別物件也不會存在
9-1-1 巢狀類別 - 宣告 巢狀類別是在類別宣告中有另一個類別宣告 Order 類別中有 OrderStatus 類別, 如下所示 : class Order { // Order 外層類別 class OrderStatus { // OrderStatus 內層類別
9-1-1 巢狀類別 - 特點 巢狀類別強調類別之間的關係 例如 : 訂單擁有訂單狀態, 所以 OrderStatus 類別是 Order 類別的一部分 巢狀類別的內層類別也是外層類別的成員, 所以其他成員可以存取或呼叫內層類別的成員變數和方法, 就算宣告成 private 也一樣可以 ; 反之, 內層類別的方法也可以直接存取其他成員變數和呼叫成員方法 在 Java 程式檔案只允許一個宣告成 public 的類別, 如果巢狀類別宣告成 public, 內層類別也一樣擁有 public 存取權限, 換句話說, 我們可以讓同一個程式檔案的多個類別擁有 public 存取權限
9-1-1 巢狀類別 - 類別檔 因為 Java 程式的巢狀類別擁有兩個類別宣告, 在編譯成 Java 類別檔案.class 後, 也會產生 2 個類別檔, 如下所示 : Order.class Order$OrderStatus.class Order.class 是外層類別的類別檔案 ; Order$OrderStatus.class 是內層類別的類別檔案
9-1-2 內層類別的使用 - 說明 巢狀類別的內層類別是外層類別的零件, 也就是其一部分, 所以不能擁有宣告 static 靜態的類別變數和方法, 而且只有在外層類別的物件存在時, 內層類別才會存在 在第 9-1-1 節的範例是使用外層類別的物件變數來取得內層類別的物件, 在這一節我們直接在 main() 方法的程式碼建立內層類別的物件和指定成員變數值, 以便說明內層類別專屬零件的角色
9-1-2 內層類別的使用 - 範例 例如 :Payment 巢狀類別宣告, 如下所示 : class Payment { // Payment 外層類別 class Card { // Card 內層類別
9-1-2 內層類別的使用 - 建立物件 在程式碼需要先建立 Payment 物件後, 才能建立 Card 物件, 如下所示 : Payment p1 = new Payment("pay002", 5600.0); Payment.Card master = p1.new Card(); 程式碼使用 new 運算子建立 p1 參考的 Payment 物件後, 使用 Payment.Card 宣告物件變數 master, 然後使用 p1.new 建立 Card 物件, 最後即可指定內層類別物件的成員變數值, 如下所示 : master.type = "MASTER"; master.number = "2433-4444-7890-1234";
9-2 匿名內層類別 9-2-1 類別繼承的匿名內層類別 9-2-2 實作介面的匿名內層類別 9-2-3 匿名內層類別與 this 和 final 關鍵字
9-2 匿名內層類別 Java 內層類別如果沒有命名, 稱為 匿名內層類別 (Anonymous Inner Classes), 簡單的說, 因為我們並沒有使用 class 關鍵字宣告類別名稱, 所以稱為匿名, 通常它是使用在 Java 的 Swing;Android 介面元件的事件處理, 可以簡化複雜的事件處理程式碼
9-2-1 類別繼承的匿名內層類別 - 宣告 MyInt 類別 一般來說, 匿名內層類別的使用方式和命名的內層類別相似, 不過, 匿名內層類別不能宣告新類別, 它必須繼承存在的類別, 例如 :MyInt 類別, 如下所示 : class MyInt { public int value; public MyInt(int v) { value = v; public String getresult(){return "Int:"+value;
9-2-1 類別繼承的匿名內層類別 - 建立匿名內層類別的 myint 物件 我們準備繼承 MyInt 類別來定義匿名內層類別, 和建立此繼承類別的 myint 物件, 如下所示 : MyInt myint = new MyInt(100) { ; // 覆寫方法 public String getresult() { return " 整數值 : " + value; result = myint.getresult();
9-2-2 實作介面的匿名內層類別 - 語法 匿名內層類別可以繼承現存類別, 也可以實作介面來建立物件, 其基本語法如下所示 : new 類別名稱 ( [ 參數列 ] ) { 或 : new 介面名稱 () { 實作介面的匿名內層類別隱含建立一個匿名類別 ( 不是繼承的子類別 ) 來實作介面
9-2-2 實作介面的匿名內層類別 - 宣告介面 例如 : 宣告一個 IValue 介面, 內含 value() 的介面方法, 如下所示 : interface IValue { int value();
9-2-2 實作介面的匿名內層類別 - 建立匿名內層類別的物件 使用匿名內層類別來實作 IValue 介面, 在 MyValue 類別擁有 getivalueobject() 方法, 可以傳回匿名內層類別建立的物件, 如下所示 : class MyValue { public IValue getivalueobject() { IValue temp = new IValue() { private int v = 50; public int value() { return v; ; return temp;
9-2-3 匿名內層類別與 this 和 final 關鍵 字 - this 關鍵字 this 關鍵字取得的是最接近類別的物件本身, 它只能存取到匿名內層類別建立的物件, 如果需要存取外層類別, 請加上類別名稱, 如下所示 : class MyValue { private int v = 50; public IValue getivalueobject() { final int v2 = 10; IValue temp = new IValue() { private int v = 20; public int value() { int v = 30; return MyValue.this.v + this.v + v + v2; ; return temp; MyValue 類別擁有成員變數 v, 匿名內層類別也擁有成員變數 v, 取得外層類別的成員變數 v, 需要使用 MyValue.this
9-2-3 匿名內層類別與 this 和 final 關鍵 字 - final 關鍵字 在內層匿名類別使用其所在方法的變數, 必須宣告為 final 例如 : 在 value() 方法使用 getivalueobject() 方法宣告的區域變數 v2, 如下所示 : public IValue getivalueobject() { final int v2 = 10; IValue temp = new IValue() { private int v = 20; public int value() { int v = 30; return MyValue.this.v + this.v + v + v2; ; return temp; 區域變數 v2 是使用 final 關鍵字宣告, 因為 v2 並不是直接拿到匿名內層類別中使用, 而是在匿名內層類別中複製一份, 作為成員變數來使用
9-3 多形的基礎 9-3-1 靜態與動態連結 9-3-2 Java 語言支援的多形
9-3-1 靜態與動態連結 - 靜態連結 ( 說明 ) 靜態連結 (Static Binding) 的訊息是在編譯階段, 就決定其送往的目標物件 例如 : 類別的過載方法是在編譯時就建立訊息和物件的連結, 也稱為 早期連結 (Early Binding)
9-3-1 靜態與動態連結 - 靜態連結 ( 圖例 ) 在第 7-3-2 節筆者說明的是靜態連結的過載方法, Ch7_3_2.java 程式的訊息是在編譯時就決定送達的目標物件是 mybirthday onebirthday 和 today, 如下圖所示 :
9-3-1 靜態與動態連結 - 動態連結 動態連結 (Dynamic Binding) 的訊息是直到執行階段, 才知道訊息送往的目標物件, 這就是多形擁有彈性的主要原因, 也稱為 延遲連結 (Late Binding)
9-3-2 Java 語言支援的多形 多形是物件導向程式設計的重要觀念,Java 實作多形有三種方式, 如下所示 : 方法過載 (Method Overloading): 方法過載也屬於多形, 屬於一種靜態連結的多形 類別繼承的方法覆寫 (Method overriding through Inheritance): 繼承基礎類別覆寫同名方法或實作同名的抽象方法, 就可以處理不同資料型態的物件 如果有新類別, 也只需新增繼承的子類別和建立方法 Java 介面的方法覆寫 (Method overriding through the Java Interface):Java 介面是指同一個物件擁有多種型態, 換個角度, 不同物件也可以擁有相同的介面型態, 我們一樣可以透過 Java 的介面來實作多形
9-4 多形的實作 9-4-1 使用類別繼承來實作多形 9-4-2 使用介面來實作多形
9-4-1 使用類別繼承來實作多形 - 抽象類別宣告 Shape 抽象類別是建立多形的基礎類別, 類別定義抽象方法 area(), 其宣告如下所示 : abstract class Shape { public double x; public double y; public abstract void area();
9-4-1 使用類別繼承來實作多形 - 繼承 Shape 抽象類別 在 Java 程式碼可以繼承 Shape 抽象類別來建立 Circle( 圓形 ) Rectangle( 長方形 ) 和 Triangle( 三角形 ) 三個子類別來建立多形方法, 其類別宣告如下所示 : class Circle extends Shape { public void area() { class Rectangle extends Shape { public void area() { class Triangle extends Shape { public void area() {
9-4-1 使用類別繼承來實作多形 - 建立多形方法 現在我們可以使用抽象類別 Shape 宣告物件變數 s, 如下所示 : Shape s; 上述物件變數 s 能夠參考 Circle Rectangle 和 Triangle 物件, 換句話說, 物件變數 s 也可以呼叫各物件的 area() 方法, 如下所示 : s.area(); 呼叫會依照物件變數 s 參考的物件來呼叫正確的方法 例如 : 如果 s 參考 Rectangle 物件, 就會呼叫 Rectangle 物件的 area() 方法, 這個 area() 方法就是多形, 因為多形方法是直到執行階段, 才依照實際參考的物件來執行正確的方法
9-4-1 使用類別繼承來實作多形 - 動態連結 物件呼叫一個方法就是送一個訊息給物件, 告訴物件需要執行什麼方法, 現在 s.area() 將訊息送到 s 物件變數參考的物件, 如下圖所示 :
9-4-2 使用介面來實作多形 - 介面的宣告 IArea 介面是用來建立多形的介面, 定義介面方法 area(), 其宣告如下所示 : interface IArea { void area();
9-4-2 使用介面來實作多形 - 實作 IArea 介面 在 Java 程式建立 Circle( 圓形 ) Rectangle( 長方形 ) 和 Triangle( 三角形 ) 三個類別實作 IArea 介面來建立多形方法, 其類別宣告如下所示 : class Circle implements IArea { public void area() { class Rectangle implements IArea { public void area() { class Triangle implements IArea { public void area() {
9-4-2 使用介面來實作多形 - 建立多形方法 現在我們可以使用介面 IArea 宣告物件變數 a, 如下所示 : IArea a; 上述物件變數 a 能夠參考 Circle Rectangle 和 Triangle 物件, 換句話說, 物件變數 a 可以呼叫物件的 area() 方法來建立多形
9-5 套件 9-5-1 套件的基礎 9-5-2 package 和 import 指令敘述的使用
9-5-1 套件的基礎 - 說明 套件 (Packages) 是一組相關類別和介面的集合, 提供存取保護, 可以讓其他類別使用套件中的類別和介面 簡單的說, 套件是物件導向程式設計的零件庫, 程式開發者可以直接選用套件中現成零件的各種類別, 輕鬆組合零件來建立物件集合, 完成 Java 應用程式的開發
9-5-1 套件的基礎 - 套件架構 Java 套件類似 Windows 資料夾的架構, 只是改為. 句點分隔, 以第 9-5-2 節名為 ch9_5_2.myshape 套件架構為例, 如下圖所示 :
9-5-2 package 和 import 指令敘述的使 用 - 建立套件 Eclipse IDE 可以在 Java 程式檔案前加上 package 指令敘述來建立套件, 例如 :Shape 抽象類別的宣告, 如下所示 : package ch9_5_2.myshape; public abstract class Shape { // Shape 抽象類別宣告 public double x; // X 座標 public double y; // y 座標 // 抽象方法 : 計算面積 public abstract void area(); 當 Java 程式檔案加上 package 指令敘述後, 以此例是指 Shape 類別屬於 ch9_5_2.myshape 套件的 public 成員
9-5-2 package 和 import 指令敘述的使 用 - 使用套件的類別 當在 Eclipse IDE 的 Java 專案建立套件後, 我們就可以在其他套件的 Java 程式碼使用此套件的類別, 例如 : 在預設套件 (Default Package) 新增 Ch9_5_2.java 程式檔後, 就可以使用 import 指令敘述匯入套件的類別, 如下所示 : import ch9_5_2.myshape.shape; import ch9_5_2.myshape.circle; import ch9_5_2.myshape.rectangle; import ch9_5_2.myshape.triangle; 程式碼匯入 ch9_5_2.myshape 套件的 Shape Circle Rectangle 和 Triangle 類別, 所以, 我們可以在 Java 程式宣告和建立 Circle Rectangle 和 Triangle 物件
9-5-2 package 和 import 指令敘述的使 用 - 匯入整個套件的類別 如果 Java 程式需要匯入整個 ch9_5_2.myshape 套件, 可以直接使用 * 符號代表在此套件下的所有類別, 如下所示 : import ch9_5_2.myshape.*;