1

This method is called regularly

public static void stynax(String N[]) {
    if (N[1].equals("echo")) { echo.s(); main(); }
    if (N[1].equals("detectos")) { detectos.s(); main(); }
    if (N[1].equals("getuser")) { getuser.s(); main(); }
    if (N[1].equals("exit")) { exit.s(); main(); }
    if (N[1].equals("makefile")) { makefile.s(); main(); }
    if (N[1].equals("cd")) { cd.s(); main(); }
    if (N[1].equals("system")) { system.s(); main(); }
    main();
}

How can I invoke all these methods

system.s();
echo.s();

Ect, by seeing if the class exists, then calling the corresponding method. N[1] is always the class name. The class where this method is stored is in a class called main, and the classes that are called are in a different package called Commands.

I always seem to get this error, when trying to make a Class variable, i think this is the main issue.

at java.net.URLClassLoader.findClass(URLClassLoader.java:381)

So it never gets to invoke the method.

To simplify.

1) The program gets the class name as a String as N[1]

2) It sees if the class exists

3) If the class exists it calls it by the name of the class N[1].s();

Edit: Imports used import java.io.ByteArrayOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays;

import cgameing.Commands.FileBrowser;
import cgameing.Commands.banner;
import cgameing.Commands.cd;
import cgameing.Commands.detectos;
import cgameing.Commands.echo;
import cgameing.Commands.exit;
import cgameing.Commands.getuser;
import cgameing.Commands.makefile;
import cgameing.Commands.system;

end of edit:

This one works, for anyone wanting to do the same thing

(Class.forName("commands."+N[1])).getDeclaredMethod("s", null).invoke(null,null);

Thanks everyone

4
  • you post is unclear,please modify your post to make it more clearer. Commented Jun 16, 2016 at 5:54
  • Just to clarify...do you really need to find the classes dynamically? If not, it would be much easier to map the command names to lambda functions. Commented Jun 16, 2016 at 6:25
  • lambda functions would work Commented Jun 16, 2016 at 6:29
  • can you show your imports? Commented Jun 16, 2016 at 6:38

4 Answers 4

2

You'll need to use reflection. Try something as follows. Use fully qualified class name instead of "XYZ" if your class is in a different package.

import java.lang.reflect.*;
import java.lang.*;

public class ReflectionTest {
 public static void main(String[] args)throws NoSuchMethodException,
 ClassNotFoundException,
 IllegalAccessException,
 InvocationTargetException {
  (Class.forName("XYZ")).getDeclaredMethod("ABC", null).invoke(null,null);
 }
}

class XYZ
{
  public static void ABC()
  {
    System.out.println("Lulz");
  }
}  

For your use case given your classes are in commands package (as you stated in a comment). The fully qualified name will then be commands.classname

(Class.forName("commands."+N[1])).getDeclaredMethod("s", null).invoke(null,null);
Sign up to request clarification or add additional context in comments.

1 Comment

How can i add a string array as well:
1

You can use Reflection. You have Class name coming in Array.

You can use "Class" and "Method" class. Class can determine if the class exists or not, and method can be used to call method you need to call.

    try {
            Class<?> c = Class.forName(N[1]);
            Object t = c.newInstance();

            Method[] allMethods = c.getDeclaredMethods();
         for (Method m : allMethods) {
              String mname = m.getName();
// if name matches use invoke method.
            }
        } catch (ClassNotFoundException x) {
         //handle exception
        }

Please consult API if you need to see more details.

7 Comments

this line, prevents me from doing anything Class<?> c = Class.forName(N[1]); as it always returns at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
Are you using fully qualified class name ( example a.b.c.classname)?
The classes are in a package called commands? Do i need to reference them somehow
Didnt get your question. Which classes you are asking about?
The classes that get called echo.s(); cd.s(); ect, Sorry that im not explaining this well.
|
1

I recommend you avoid using reflection if you possibly can. Better is to define the commands you expect to see - ideally in an enum.

For example:

enum Command {
    CD(FileSystem::cd),
    EXIT(Application::exit),
    MAKEFILE(FileSystem::createFile),
    ...

    private final Runnable runnable;

    Command(Runnable runnable) {
        this.runnable = runnable;
    }

    public void run() {
        runnable.run();
    }
}

You can still use the name to get the command if you wish (automatically throwing an exception if the value isn't found in the enum - which is presumably what you would want):

Command.valueOf(commandString.toUpperCase()).run();

Or call the commands directly without having to know which method they delegate to:

Command.MAKEFILE.run();

Given you are going to have a list of if statements somewhere, you might as well encapsulate that in an enum which is much more explicit than embedding the method names.

Comments

0

Okay, everyone seems to suggest reflection, there is at least one alternative way to do it, depending on whether you know your class and method names at compile time or not.

So, lets say we have this method in someclass:

    public void changeDirectory(String args) {

    //do something
}

If they are known, you could easily use method references:

    HashMap<String, Consumer<String[]>> commands = new HashMap<>();
    commands.put("cd", SomeClass::changeDirectory);
    commands.get("cd").accept(args);

The drawback would be, the method signature would have to be the same... on the other hand, if you know the exact method anyway, you could just use a switch statement and call them directly...

If you want to do it dynamically, the alternative to reflection would be MethodHandles. The advantage is that they would only check access once on creation and have some other optimizations that should make them faster than reflection in most cases.

    Class<?> dynamicallyFoundClass = Class.forName("some.package.SomeClass");
    Class<?> fixedClass = SomeClass.class;
    String methodName = "changeDirectory";
    MethodType type = MethodType.methodType(void.class, String.class);

    handles.put("cd", lookUp.findStatic(dynamicallyFoundClass, methodName, type));

    handles.get("cd").invoke(args);

But how complicated an approach you have to use would depend on what you know at compile time and what has to be found at runtime.

3 Comments

This could work as well, as all the classes use the same 3 methods
I didn't suggest reflection :-)
I noticed, but your answer did not exist while I was writing that. ;)