Rudy Garcia
Rudy Garcia

Reputation: 532

Call a class method from a java variable

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

Answers (1)

Costi Ciudatu
Costi Ciudatu

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

Related Questions