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

Java - How to invoke a method from another class, with the class name and method name as a string

定期调用此方法

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

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

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

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

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

简化。

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

2) 查看class是否存在

3) 如果 class 存在,它通过 class N[1].s();

的名称调用它

编辑:使用进口 导入 java.io.ByteArrayOutputStream; 导入 java.io.FileWriter; 导入 java.io.IOException; 导入 java.io.PrintStream; 导入 java.io.PrintWriter; 导入 java.lang.reflect.InvocationTargetException; 导入 java.lang.reflect.Method; 导入 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);

谢谢大家

您可以使用反射。 数组中有 Class 个名称。

您可以使用 "Class" 和 "Method" class。 Class可以判断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。

您需要使用反射。尝试如下操作。如果您的 class 在不同的包中,请使用完全限定的 class 名称而不是 "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");
  }
}  

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

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

我建议您尽可能避免使用反射。更好的方法是定义您希望看到的命令 - 最好在 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 中,这比嵌入方法名称要明确得多。

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

所以,假设我们在一些class:

中有这个方法
    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);

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