如何使用Java反射在运行时调用每个方法具有不同参数的类的方法?

时间:2018-10-14 16:25:36

标签: java reflection

我正在研究硒的关键字驱动框架。 我在单独的类中编写了方法。 以下是包含用于打开主页,输入用户名和密码并单击登录按钮的操作方法的类。

package actions;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class adminlogin {
    WebDriver driver;
    public adminlogin(WebDriver driver){
        this.driver = driver;
    }
    public void adminopenhomepage() {
        driver.get("http://localhost/carrental/admin/");
    }
    public void adminenterusername(WebElement username) {
        username.sendKeys("admin");
    }
    public void adminenterpassword(WebElement password) {
        password.sendKeys("Test@12345");
    }
    public void adminclickloginbutton(WebElement loginbutton) {
        loginbutton.click();
    }
    public void adminclosebrowser() {
        driver.close();
    }
}

我在列表中有关键字,并且遍历关键字并使用反射调用上述方法。 我想做的一种方法是在运行时获取参数类型和参数数量,以便我可以相应地传递参数。我正在尝试使用getDeclaredMethod(keyword)获取该方法,但这仅适用于那些没有诸如adminopenhomepage()之类的参数的方法,并且对所有其他接受参数的方法均不提供此类方法。谁能告诉我如何解决这个问题?

for(String str : originalkeywords) {
    String keyword = str;
    String actioncl = keywordvsac.get(keyword);
    String objectcl = keywordvsor.get(keyword);

    Class<?> cls = Class.forName("actions."+actioncl);
    Method methodcall = cls.getDeclaredMethod(keyword);

    Parameter[] parameters = methodcall.getParameters();        
    System.out.println(Arrays.toString(parameters));
}

谢谢。

2 个答案:

答案 0 :(得分:1)

要通过反射调用方法,您需要三件事:

  1. 对象的类名
  2. 为其调用方法的类实例
  3. 方法参数。

直接从official documentation中获取示例来调用方法,只需编写:

    Class<?> c = Class.forName(args[0]);
    Class[] argTypes = new Class[] { String[].class };
    Method main = c.getDeclaredMethod("main", argTypes);
    String[] mainArgs = Arrays.copyOfRange(args, 1, args.length);
    System.out.format("invoking %s.main()%n", c.getName());
    main.invoke(null, (Object)mainArgs);

要显示参数名称,只需查阅Java官方文档中的another page即可。

希望对您有帮助。

答案 1 :(得分:0)

您可以使用AdminLogin.class.getDeclaredMethods()并使用for循环将所有方法映射到某些操作,然后您可以使用method.getParameters()读取参数,但请注意,参数可能没有名称-必须在中启用使用-parameters标志的编译器。

概念证明:

Map<String, Callable> mappedMethods = new HashMap<>(); // you can use runnable etc, I used callable as I don't want to catch exceptions in this example code - you should.
AdminLogin instance = new AdminLogin();
WebElement usernameElement = null; // idk how you get instance of this
WebElement passwordElement = null; // idk how you get instance of this
for (Method method : AdminLogin.class.getDeclaredMethods()) {
   Parameter[] parameters = method.getParameters();
   Object[] args = new Object[parameters.length];
   for (int i = 0; i < parameters.length; i++) {
       Parameter parameter = parameters[i];
       if ((parameter.getType() == WebElement.class) && parameter.getName().equals("username")) {
           args[i] = usernameElement;
       }
       else if ((parameter.getType() == WebElement.class) && parameter.getName().equals("password")) {
           args[i] = passwordElement;
       } else {
           // log some info/throw exception, whatever you need for methods that can't be mapped
           break;
       }
   }
   mappedMethods.put(method.getName(), () -> method.invoke(instance, args));
}

现在您可以从地图上按名称调用该可调用对象。

但是请注意,您应该在此处添加更多的抽象,因为如果您有更多的参数类型需要处理或为每个类复制此代码,那么在ifs的墙将是一个坏主意。 还可以阅读有关Java中注释的信息,它们对于标记类似的特殊方法和参数很有用,但也不要过度使用它们。

还请注意,getDeclaredMethods返回的方法没有特定的顺序,并且肯定不按与类中声明的顺序相同的顺序返回。