本文索引
一、基礎類別構造
二、另外一種用法
三、傳入參數並修改
四、結論
日期:2020 年 2 月 5 日
一、基礎類別構造
在 Java 中,沒有並沒有類似於 C/C++ 的 " * " 運算元來定義物件的位置,最多只能使用參照的方式傳遞物件。而我們也將用此特性來模仿於類似 C/C++ 函式指標的功能。
我們先定義第一個介面:
/** 最基本的介面
利用此介面來達成類似指標的功能 */
interface Action{
public void doAction();
}
我們可以藉由這個介面,來達到類似函式指標的功能。
再來我們在定義一個類別:
/** 第一種類別 */
class FooA{
/** 建構子
* @param action 愈設定的動作 */
public FooA(Action action){
//直接執行動作
//注意!這裡是宣告在建構子裡,所以之後會直接執行
action.doAction();
}
}
接下來我們這樣執行:
//直接宣告匿名類別至 fooA1
FooA fooA1 = new FooA(new Action(){
//宣告要執行的動作
public void doAction(){
System.out.println("第 1 種寫法");
}
});
這裡的意思其實就是有點像是,fooA1 是一台新的印表機,沒有任何的功能在裡面。而 new Action() 裡面這段就是在告訴這台印表機( fooA1 )只能印出 "第 1 種寫法"。
整個執行後的結果:
結果:
第 1 種寫法
二、另外一種用法
因為根據上面的寫法,我們將 Action 寫在建構子裡,所以他只會在物件被建構時執行一次,那假如我們想要它可以一直被使用時該怎麼辦?
我們可以這樣宣告類別:
/** 第二種類別 */
class FooB{
public FooB(){}
/** 儲存我們要動作的函式 */
private Action action;
/** 設定要動作的函式
* @param action 愈設定的動作 */
public void setAction(Action action){
this.action = action; //類似於 (*ptr) = function
}
/** 執行動作 */
public void doAction(){
action.doAction();
}
}
在來我們這樣執行:
//先宣告要執行的動作
Action action3 = new Action(){
public void doAction(){
System.out.println("第 3 種寫法");
}
};
FooB fooB1 = new FooB();
fooB1.setAction( action3 ); //設定要動作的函式
fooB1.doAction(); //執行第一次
fooB1.doAction(); //執行第二次
整個執行後的結果:
結果:
第 3 種寫法
第 3 種寫法
因為我們執行的兩次 fooB1.doAction();
所以它總共印出了兩次。這個與上面不同的地方在於,我們多了成員變數儲存 Action 讓它可以在 FooB 裡的任何函式中執行。
三、傳入參數並修改
我們上面的例子都是沒有傳入數值的情況,那假如我們 FooB 裡面有個數值 Count ,
我們想要讓它被做任運算,而不增加 FooB 的成員函式。
我們先這樣定義Action:
interface Action{
/** 宣告虛擬函式,並且接收一個整數參數
* @param num 欲做運算的數字 */
public void doAction( int num );
}
我們這樣定義FooB:
class FooB{
/** FooB 裡的成員變數 */
protected int count = 10;
/** 儲存我們要動作的函式 */
private Action action;
/** 建構子 */
public FooB(){};
/** 設定要動作的函式
* @param action 愈設定的動作 */
public void setAction(Action action){
this.action = action;
};
/** 動作
* @param num 要做運算的數字 */
public void doAction( int num ){
action.doAction( num );
}
/** @return 回傳 Count */
public int getCount(){ return count; }
}
在來是執行的部分:
//先將 FooB 宣告出來
FooB fooB = new FooB();
//設定第一個運算方法,我們這裡是用 "加" 的
fooB.setAction(
new Action(){
public void doAction( int num ) {
//這裡比較特別的是 fooB.count 與 num 做加法
fooB.count += num;
}
}
);
System.out.println( "做加法" );
System.out.println( "執行前:目前 fooB Count = " + fooB.getCount() + "\n" );
fooB.doAction( 5 );
System.out.println( "執行後:目前 fooB Count = " + fooB.getCount() + "\n" );
System.out.println( "==============================================\n" );
//設定第一個運算方法,我們這裡是用 "乘" 的
fooB.setAction(
new Action(){
public void doAction( int num ) {
//這裡比較特別的是 fooB.count 與 num 做乘法
fooB.count *= num;
}
}
);
System.out.println( "做乘法" );
System.out.println( "執行前:目前 fooB Count = " + fooB.getCount() + "\n" );
fooB.doAction( 10 );
System.out.println( "執行後:目前 fooB Count = " + fooB.getCount() + "\n" );
結果:
做加法
執行前:目前 fooB Count = 10
執行後:目前 fooB Count = 15
==============================================
做乘法
執行前:目前 fooB Count = 15
執行後:目前 fooB Count = 150
四、結論:
根據以上執行我們可以看到,我們在只使用一個 doAction(); 的函式就達到了加法與乘法,
雖然這樣看起來感覺就像是脫褲子放屁,但是因為我們這裡只是使用一個簡單的整數運算,
假如這時候我說要一個 fooB1 做 count + num 、
fooB2 做 count + num x 8 、 fooB3 做 count + num x 5
那這樣我們不就要在幫它多設計其它的可能,有些人可能會用 if,有些人也有可能會幫它們各做一個函式,那實在很麻煩
。尤其是在這種物件導向的程式語言中,多了許多功能相似,但是又有點不太一樣的函式,在建構虛擬類別或實行多型時可能都會遇到一些問題。