2014-10-26 93 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

相关问题