2007年7月19日 星期四

Java 學習筆記 (2) - Object Oriented

this

關鍵字 this 在 Java 中,為參考到呼叫 method 的實際 object 之用。

假設在某個 class 中,分別有以下內容:

attribute
  • myName
  • myAge
method
  • showName()
  • showAge()

當使用該 class 產生出兩個 object 後,每個 object 擁有各自的 attribute,亦即 myName、myAge 各有兩份;但 showName()、showAge() 兩個 method 卻還是只佔了一份記憶體空間。

因此就會有問題出現了,那要如何判斷是那個 object 呼叫 method 的呢? 答案就是 this 關鍵字!

JavaWorld@TW 有一篇文章說明的很詳細:給新手 - this 到底是什麼?


Overload

此機制可用來統一 method 的名稱,但卻可根據參數列各參數型態、數量的不同(僅有 return type 不同,compiler 會把 methods 視為相同而產生錯誤喔!)而自動呼叫對應的 method,例如:String class 中的 valueOf() 方法。

以下用一段程式碼測試 overload 與 boxing 機制的搭配:
public class OverloadDemo {
public static void main(String[] args) {
//測試 overload & boxing
myMethod(10); //int 版本被呼叫
myMethod(new Integer(10)); //Integer 版本被呼叫
}

public static void myMethod(int i) {
System.out.println("int 版本被呼叫");
}

public static void myMethod(Integer i) {
System.out.println("Integer 版本被呼叫");
}
}
【註】以前竟然把這個機制當作是 Polymorphism(多型),真是完全搞錯....Orz


Variable-length Argument (不定長度引數)

當呼叫 method 但 argument 的數量無法事先確定時,這種機制就很好用啦! 這是在 J2SE 5.0 版以後才提供的功能,所使用的關鍵字為「...」,以下用範例說明:
public class VarLenArgs {
public static void main(String[] args) {
//2個參數
System.out.println("1 + 2 = " + sum(1, 2));
//3個參數
System.out.println("1 + 2 + 3 = " + sum(1, 2, 3));
//4個參數
System.out.println("1 + 2 + 3 + 4 = " + sum(1, 2, 3, 4));
}

//Variable-length Arguments
public static int sum(int... intNums) {
int intSum = 0;
for(int intNum : intNums)
intSum += intNum;
return intSum;
}
}
【註】有一點很重要,若要使用不定長度的引數時,必須宣告在參數列的最後一個! 否則會產生錯誤!


Polymorphism (多型)

Polymorphism 即是用相同的 interface 來操作不同的 object,進而降低對 interface 的依賴程度,增進程式架構的彈性與可維護性,可透過 abstract class(抽象類別) 或是 interface(介面) 兩種方式來達成,以下分別用範例來介紹:

使用 abstract class (抽象類別)


AbstractGuessGame.java (定義共通 interface 的 abstract class)
public abstract class AbstractGuessGame {
private int number;

public void setNumber(int number) {
this.number = number;
}

public void start() {
showMessage("歡迎");
int guess = 0;
do {
guess = getUserInput();
if(guess > number)
showMessage("輸入的數字較大");
else if(guess < number)
showMessage("輸入的數字較小");
else
showMessage("猜中囉!");
} while(guess != number);
}

protected abstract void showMessage(String message);
protected abstract int getUserInput();
}
TextModeGame.java (繼承 abstract class 並實作其 abstract method)
import java.util.Scanner;

public class TextModeGame extends AbstractGuessGame {
private Scanner scanner;

public TextModeGame() {
scanner = new Scanner(System.in);
}

protected void showMessage(String message) {
for(int i = 0 ; i < message.length() ; i++)
System.out.print("*");
System.out.println("\n" + message);
for(int i = 0 ; i < (message.length() * 2) ; i++)
System.out.print("*");
}

protected int getUserInput() {
System.out.print("\n輸入數字:");
return scanner.nextInt();
}
}
GuessGameDemo.java (使用 Parent Class 宣告 object 來作為 interface 操作)
public class GuessGameDemo {
public static void main(String[] args) {
AbstractGuessGame guessGame = new TextModeGame();
guessGame.setNumber(50);
guessGame.start();
}
}
從上面可以看出,Polymorphism 透過 abstract clsas 來實作的方式,可透過 Parent Class 的型態,去操作 Child Class 中重新被定義的方法,亦即透過 Parent Class 的型態,進行多型操作。

使用 interface (介面)

IRequest.java (interface 的定義)
public interface IRequest {
public void execute();
}
HelloRequest.java (實作 interface 的 class)
public class HelloRequest implements IRequest {
private String name;

public HelloRequest(String name) {
this.name = name;
}

public void execute() {
System.out.printf("哈囉 %s! \n", name);
}
}
WelcomeRequest.java (實作 interface 的 class)
public class WelcomeRequest implements IRequest {
private String place;

public WelcomeRequest(String place) {
this.place = place;
}

public void execute() {
System.out.printf("歡迎來到 %s!\n", place);
}
}
RequestDemo.java (透過 interface 達成多型)
public class RequestDemo {
public static void main(String[] args) {
for(int i = 0 ; i < 10 ; i++) {
int n = (int)(Math.random() * 10) % 2;
switch(n) {
case 0:
//傳入實作 IRequest 介面的 HelloRequest
doRequest(new HelloRequest("Hello"));
break;
case 1:
//傳入實作 IRequest 介面的 WelcomeRequest
doRequest(new WelcomeRequest("Welcome"));
break;
}
}
}

//參數中定義的是 IRequest 介面
//只要有實作 IRequest 介面的 class 所產生的 object,都可以傳進來
public static void doRequest(IRequest request) {
request.execute();
}
}
將 interface 與 abstract class 兩種實作 Polymorphism 的方式拿來比較,可以看出透過 abstract class 去實作,會造成依賴某個特定型別;但若是透過 interface 來實作,只要 class 有實作該 interface 即可,不需要是特定 class 所產生出來的 obejct,因此在運用上更多了一些彈性。

因此,建議實作 Polymorphism 時,多用 interface 讓設計架構上更為彈性。


觀念釐清
  1. 若是 override Parent Class 的 method,只能擴大其 method 的權限(例如:protected -> public),不能縮小其權限(例如:public -> private)
  2. static method 是無法被 override 的
  3. Object Class 是所有 Java Class 的 Parent Class,當定義一個 Class 後,預設即為繼承 Object Class


推薦參考連結

沒有留言:

張貼留言