Java - 如何从另一个类调用方法,类名和方法名称为字符串

时间:2016-06-16 05:36:23

标签: java arrays invoke

定期调用此方法

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();
}

如何调用所有这些方法

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

Ect,通过查看该类是否存在,然后调用相应的方法。 N [1]始终是类名。存储此方法的类位于名为main的类中,而调用的类位于名为Commands的不同包中。

我似乎总是得到这个错误,在尝试创建一个Class变量时,我认为这是主要问题。

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

所以它永远不会调用该方法。

简化。

1)程序将类名称作为字符串获取为N [1]

2)它看是否存在类

3)如果该类存在,则按类N [1] .s();

的名称调用它

编辑:使用的导入     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;

编辑结束:

这个适用于任何想要做同样事情的人

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

谢谢大家

4 个答案:

答案 0 :(得分:2)

你需要使用反射。尝试以下内容。如果您的类位于不同的包中,请使用完全限定的类名而不是"XYZ"

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");
  }
}  

对于您的用例,您的课程是commands包(正如您在评论中所述)。完全限定名称将为commands.classname

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

答案 1 :(得分:1)

您可以使用反射。 您有类名称Array。

您可以使用“Class”和“Method”类。类可以确定类是否存在,并且可以使用方法调用需要调用的方法。

    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
        }

如果您需要查看更多详细信息,请参阅API。

答案 2 :(得分:1)

我建议你尽可能避免使用反射。更好的方法是定义您希望看到的命令 - 最好是enum

例如:

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();
    }
}

如果您愿意,您仍然可以使用该名称来获取命令(如果在枚举中找不到该值,则自动抛出异常 - 这可能是您想要的):

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

或直接调用命令,而无需知道他们委派的方法:

Command.MAKEFILE.run();

鉴于您将在某处获得if语句的列表,您可以将其封装在enum中,这比嵌入方法名称更明确。

答案 3 :(得分:0)

好的,每个人似乎都建议反思,至少有一种替代方法可以做,这取决于你是否在编译时知道你的类和方法名称。

所以,假设我们在某个类中有这个方法:

    public void changeDirectory(String args) {

    //do something
}

如果已知它们,您可以轻松使用方法引用:

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

缺点是,方法签名必须相同... 另一方面,如果你知道确切的方法,你可以使用switch语句直接调用它们......

如果你想动态地做,反射的替代方法是MethodHandles。优点是,他们只会在创建时检查一次访问,并进行一些其他优化,应该使它们比大多数情况下的反射更快。

    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);

但是,您必须使用的方法有多复杂取决于您在编译时所知道的以及在运行时必须找到的内容。