2014-10-26 25 views
1

我對Java相當陌生,在大學時學過它,但自那之後就沒有真正觸及它。我正在嘗試再次學習,我正在製作一個簡單的客戶端服務器遊戲,但遇到了一些問題。從java變量中調用一個類的方法

基本上我所要做的就是讓我有一個類的所有命令玩家可以做,我想調用基於他們發送服務器的命令。

客戶端發送消息,如「殺怪」。

服務器應該拆分字符串並調用方法kill('monster');

我明顯可以用開關映射出命令,但我想嘗試反射並根據發送的字符串動態調用方法。這會讓我的代碼更清潔一點,因爲我只需要在沒有這種方法時添加新的方法和處理程序。在PHP中,這很簡單,你可以通過說myclass - > $ mymethod('string')來調用函數。

我已經將客戶端和服務器設置爲讓客戶端輸入一個字符串並將其發送到服務器,並將其保存在變量消息中。

我在Java中已經嘗試是這樣的:

String[] parts = message.split(" ", 2); 
Command.class.getMethod(parts[0].toLowerCase(), String.class).invoke(parts[1].toLowerCase()); 

但是,這並不爲我工作,我得到一個錯誤

java.lang.IllegalArgumentException: object is not an instance of declaring class 

Command.java簡單,就是:

public class Command { 
    public Command(){ 

    } 

    public void kill(String monster){ 
     System.out.println(monster + " Kills you!"); 
    } 
} 

我在做什麼錯。我特別不確定的一件事是getMethod()的第二個參數。

+2

有幾種方法可以完成你想要做的事情。一個是從命令到創建接口的顯式映射,它們調用這些命令。正如你所建議的那樣,另一種方法是反思。但是,我會提醒你注意反射方法......如果你不仔細限制哪些方法被調用(例如,白名單或客戶端可以調用的方法需要註釋),你可能會最終無意中允許客戶端調用服務器中定義的任意方法。 – 2014-10-26 23:10:30

+2

Java不是一種動態語言 - 沒有辦法簡單地做到這一點。選項包括使用反射,使用方法名稱作爲關鍵字(開關或映射)選擇的回調或實現從輸入分析實例的「動作」接口的枚舉。我不會推薦嘗試對初學者實施這些替代方案。 – Bohemian 2014-10-26 23:11:03

回答

2

錯誤本身是因爲您要調用的方法是實例方法,並且您需要該命令的一個實例來調用它(現在,您試圖調用kill方法String類的實例 - 您傳遞的第一個參數)。詳情請參閱this answerMethod.invoke() javadoc。但如果你需要在應用程序代碼中進行反射,通常意味着你不在正確的軌道上(至少從OOP的角度來看)。

你的具體情況,各種命令應該建模爲同一個類的方法,但由於實例它(見command pattern,例如,甚至strategy pattern,作爲有用的例子)。

由於您只想讓每個命令一個實例(和你需要找到名稱正確的命令),一個enum很可能是這裏最合適的選擇:

enum Command { 
    KILL { 
     @Override public void execute(String arg) { 
      System.out.printf("%s is dying...", arg) 
     } 
    }, 
    KISS { 
     @Override public void execute(String arg) { 
      System.out.printf("I'm kissing %s!", arg) 
     } 
    }; 

    public abstract void execute(String arg); 
} 

然後,你的代碼變得簡單地說:

Command.valueOf(parts[0].toUpperCase()).execute(parts[1].toLowerCase()); 
+0

這是一個很好的迴應,不僅解決了我的問題,而且提出了一個比我想要做的更簡單的方法, – 2014-10-27 01:52:31

相關問題