本文索引
一、基礎類別構造
二、另外一種用法
三、傳入參數並修改
四、結論
日期: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,有些人也有可能會幫它們各做一個函式,那實在很麻煩 。尤其是在這種物件導向的程式語言中,多了許多功能相似,但是又有點不太一樣的函式,在建構虛擬類別或實行多型時可能都會遇到一些問題。