Reputation: 532
I am fairly new to Java, I learned it in college but haven't really touched it much since. I am trying to learn it again and I am making a simple client server game but have run into some issues.
Basically what I am trying to do is make it so that I have a class with all the commands a player can do and I want to call that command based on what they send the server.
Client sends message such as "kill monster".
Server should split the string and call the method kill('monster');
I could obviously map out the commands with a switch but I wanted to try out reflection and dynamically calling the method based on the string sent. This would make my code a bit cleaner I think since I would only need to add new methods and a handler for when there is no such method.
In PHP this is really easy you can just call the function by saying myclass->$mymethod('a string');
I already have the client and server set up to have the client type a string and send it to the server which saves it in the variable message.
What I have tried in Java is this:
String[] parts = message.split(" ", 2);
Command.class.getMethod(parts[0].toLowerCase(), String.class).invoke(parts[1].toLowerCase());
But this does not work for me and I get an error
java.lang.IllegalArgumentException: object is not an instance of declaring class
Command.java is simple and is this:
public class Command {
public Command(){
}
public void kill(String monster){
System.out.println(monster + " Kills you!");
}
}
What am I doing wrong. The one thing I am particularly not sure about is the second parameter of getMethod().
Upvotes: 1
Views: 173
Reputation: 38265
The error itself is because the method that you're trying to invoke is an instance method, and you need an instance of that command to invoke it (right now, you're trying to invoke the kill
method on an instance of the String
class -- the first argument you're passing). See this answer or the Method.invoke() javadoc for details.
But if you need reflection in your application code, it usually means you're not on the right track (at least from an OOP point of view).
In your particular case, the various commands should not be modeled as methods of the same class, but as instances of it (see command pattern, for instance, or even strategy pattern, as useful examples).
Since you only want to have one instance per command (and you need to find the proper command by name), an enum
would probably be the most suitable choice here:
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);
}
Then, your code becomes simply:
Command.valueOf(parts[0].toUpperCase()).execute(parts[1].toLowerCase());
Upvotes: 2