[java] How do I call a method in java when I don't know what it is beforehand?

Started by
18 comments, last by Shaggy999 22 years, 2 months ago
I am wondering if something like this is even possible. In VB there is a way to call a method by using CallByName or something like that where you just pass the name of the method as a string. Is there a similiar way to do that with the name of a method for a class?
Advertisement
Check out the Class and Method classes in the java.lang.reflect package.
The java.lang.reflect package will do what you''re asking, but be aware that it''s sloooow. There are faster ways of calling methods dynamicly. Polymorphism, an indexed list of Runnable objects, etc.
As always, performance test your code, see what works best in your situation.

"If consquences dictate our course of action, it doesn''t matter what''s right, it''s only wrong if you get caught."
- Tool
"There is no reason good should not triumph at least as often as evil. The triumph of anything is a matter of organization. If there are such things as angels, I hope that they're organized along the lines of the mafia." -Kurt Vonnegut
quote:Original post by WayfarerX
The java.lang.reflect package will do what you''re asking, but be aware that it''s sloooow. There are faster ways of calling methods dynamicly. Polymorphism, an indexed list of Runnable objects, etc.
As always, performance test your code, see what works best in your situation.

"If consquences dictate our course of action, it doesn''t matter what''s right, it''s only wrong if you get caught."
- Tool


I am trying to right a script engine and I wanted to do this instead of using a bunch of huge select case statements. I don''t think I could use polymorphism for that. I have not had a lot of experience w/ multi-threading and haven''t heard about indexing a list of runnable objects? What is that? Can you provide to a link with some info on that?

Anyway, thanks a bunch. The reflection API is working out for me.

This post might be a little long-winded, so beware.

To use an indexed list of Runnables is easy and doesn't require any multi-thread code.
java.lang.Runnable is a simple interface that declares a single function: public void run(). Classes that implement the Runnable interface are most commonly passed to new Threads so that the Thread can call the Runnable's run() method in a new thread. However, the runnable object is also a tool you can use to simulate passing pointers to functions like in C.
EXAMPLE: Lets say you're writing a script for an AI. There are three methods the script should be able to call "MoveForward()", "MoveLeft()", & "MoveRight()". First thing you do is create 3 classes that implement Runnable, on for each method:

  public class MForwardRunner implements Runnable {  //...  public void run () {    // Call your moving forward code  }  //...}public class MLeftRunner implements Runnable {  //...  public void run () {    // Call your moving left code  }  //...}public class MRightRunner implements Runnable {  //...  public void run () {    // Call your moving right code  }  //...}   


Next, create a Hashtable with all of your functions indexed by their name:

  Hashtable scriptFuncTbl = new Hashtable();scriptFuncTbl.put("MoveForward()", new MForwardRunner());scriptFuncTbl.put("MoveRight()", new MRightRunner());scriptFuncTbl.put("MoveLeft()", new MLeftRunner());   


Then, to call a function from a script, just look up the Runnable in the hashtable and run it

  void runScriptFunc (String funcName){  Runnable r = (Runnable)scriptFuncTbl.get(funcName);  if (r != null) r.run();}   


This should work fine, and it will probably be faster than the reflection API (but be sure and test, test, test), but this isn't how I'd nessicarily do it.

If I was building a scripting language to run in a Java app (which I have done before), I would think about the fact that Java itself is essintially a scripting language, it just get's compiled into byte codes beforehand. Java also has all of the features you could want in a full-featured scripting language, is heavily supported by an industry full of developers, and will probably beat the pants off any generalized language you or I could come up with and implement when it comes to speed.
So think about this. You create an abstract class called "AIScript" or whatever. In this class you implement a bunch of methods that the script should be able to call (like an IsEnemyInFrontOfMe() function or the MoveForward/Right/Left functions from earlier). Finally, you add one abstract method called "RunScript()" or something.
Then, to actually make a script, you create another class that sub-classes AIScript and implements the RunScript() function. What does this do for you?
1) Easy upkeep of the interface scripts have into your game. Simply change the AIScript class and viola! No hashtables, no reflection API.
2) You can completely skip writing the parser/lexer/etc. for your engine, saving mucho development time.
3) The compiled Java code will run faster than just about anything you could implement.

You could even have a little utility that would take code written by level designers in the format:

  // AI Script filewhile (IsAlive()){  if (IsEnemyInFrontOfMe())  {    Attack();  }  else  {    FaceTowardsEnemy();    MoveForward();  }}   


and flow it into a template file:

  class AISCRIPT_[ScriptFileName] extends AIScript{  public void runScript ()  {    [ScriptContents]  }}   


replacing "[ScriptFileName]" with the name of the script file and "[ScriptContents]" with the contents of the script. Compile and you have a class file that is loadable into your game. This also makes it easier for users to mod your game since the "scripting language" you're using is completely documented in hundreds of books and thousands of online tutorials.

Just food for thought (the length of this post would imply a feast for thought). If you have any further questions about this stuff just post here or email me at wayfarerx@hotmail.com.

"If consquences dictate our course of action, it doesn't matter what's right, it's only wrong if you get caught."
- Tool

Edited by - wayfarerx on September 10, 2001 4:51:03 PM
"There is no reason good should not triumph at least as often as evil. The triumph of anything is a matter of organization. If there are such things as angels, I hope that they're organized along the lines of the mafia." -Kurt Vonnegut
If you want to really write a good scripting language, read up on the java virtual machine specification . This contains information on writing your own byte code class files. Then you can overload a ClassLoader that can load your own custom scripts which are compiled to class byte code. To interogate an object''s methods, just use the getClass() method. Then use the methods of the class to get all the methods and fields. From the Method class returned by getMethod("name"), you can call invoke( Object, Object[]) with object referring to the target object, and Object[] referring to an array of arguments for the functions.
Sorry to dig up an old post...

I''m a relative java newbie, and I really like the method of scripting WayfarerX has described. One question though, is it possible to compile a ''script'' into a class file, and the load and create an instance of it during runtime? I''m working on a simple multiplayer game, and it would be nice if I could add new scripts in without having to restart the game.
Yes, it is very possible. Dynamic compilation and class loading can get very good performance from scripting. The solution can also be used even when you do not use Java as the scripting language, such as when you use an entirely graphical tool to create the scripts. You just need some way to create JVM bytecode from whatever representation the script is created in.
Well, if its possible to do it in java, how do I go about it? Are there classes within the java api that can be used to compile during runtime?
No compiler classes are included in the standard Java API so you will either have to write your own or use 3rd party software. There might be publicly available packages out there that you can integrate in your product or you can possibly use the javac compiler from Sun, I think they allow you to distribute it with your apps nowdays.

This topic is closed to new replies.

Advertisement