【问题标题】:how to call a java method using a variable name?如何使用变量名调用java方法?
【发布时间】:2011-05-07 12:21:36
【问题描述】:

假设我有 Method1(void)、Method2(void)...

有没有办法我可以选择其中一个变量?

 String MyVar=2;
 MethodMyVar();

【问题讨论】:

  • 可以,但为什么要这样做?
  • 我实际上遇到过一个案例,使用反射 + HashMap 比使用大量 if/else 字符串比较和条件方法调用更有意义。
  • @cHao:当然更好的方案是编写一个接口并使用 HashMap 来存储该接口的对象作为 lambda 函数的模拟。
  • @Mark E:如果我想调用的所有方法都在同一个对象上,则不会。使用接口意味着有一个单独的类来表示每个方法,这意味着一大堆类和一大堆设置工作来完成我用注释、反射和 HashMap 用更少的代码更可靠地完成的工作。除非我理解错了。
  • “你为什么要这样做”的回答是徒劳的、粗鲁的和苹果式的。

标签: java variables methods


【解决方案1】:

使用反射:

Method method = WhateverYourClassIs.class.getDeclaredMethod("Method" + MyVar);
method.invoke();

【讨论】:

  • +1,需要注意的是反射可能很慢,并且编译器不再强制执行类型安全。
  • WRT 他的例子,这不会寻找'Method2'作为方法吗?
  • MethodClass 有什么依赖关系?我正在尝试使用它,但出现错误:non-static method getDeclaredMethod cannot be referenced from a static context
  • @hellyale:这应该是一个实例方法,你必须在你的类上获取类对象并调用它的方法。
  • @T.Todua:可能是几十倍,甚至是几百倍。如果您一次性使用它,您将不会注意到差异,并且灵活性非常值得可能的额外微秒。但是,在一个紧密的循环中,它可能很重要。
【解决方案2】:

只能通过反思。请参阅java.lang.reflect 包。

你可以试试这样的:

Method m = obj.getClass().getMethod("methodName" + MyVar);
m.invoke(obj);

如果方法有参数并且缺少各种异常处理,您的代码可能会有所不同。

但是问问你自己这是否真的有必要?可以对您的设计进行一些更改以避免这种情况。反射代码比较难理解,比只调用obj.someMethod()慢。

祝你好运。快乐编码。

【讨论】:

【解决方案3】:

您可以使用策略设计模式和从您拥有的字符串到相应具体策略对象的映射。这是安全有效的手段。

所以,请查找HashMap<String,SomeInterfaceYouWantToInvokeSuchAsRunnableWithPseudoClosures>

例如,类似于:

final static YourType reciever = this;
HashMap<String,Runnable> m = new HashMap<String,Runnable> {{
    put("a", new Runnable() {
       @Override public void run () {
         reciever.a();
       }
    });
    ....
}};
// but check for range validity, etc.
m.get("a").run()

您也可以使用反射或“反转”问题并使用多态性

【讨论】:

  • 我将override 更正为Java 的@Override,但这确实没有必要。在某些相关情况下,枚举也可能有用。反射当然是邪恶的。
  • 在问这个问题之前我只做了少量的研究,但为什么反射是邪恶的?它对我来说似乎非常强大,并且看起来它可以让编写一些代码变得更容易。老实说,你在上面写的是我整个星期看到的最酷的东西。不过,我有一个问题:您使用哈希图的方法是否比同一线程上的反射示例更好?
  • add("a", ... 应该是put("a", ...
  • @michaelsnowden 反射被认为是邪恶的,因为它会破坏封装,并消除编译器时检查的好处。还有其他策略,例如上面提到的策略,可以通过更多配置实现相同的结果。虽然我承认我理解“您可以使用在类上定义的任何公共函数名称”(类作为配置)的吸引力,但它削弱了 Java 的优势之一。
  • @Fleep 是的,在我问这个问题后编码了 4 年,我肯定已经意识到为什么它被认为是邪恶的哈哈
【解决方案4】:

如果静态方法的第一个参数为null,我不确定method.invoke() 接受的答案如何工作(尽管放置虚拟值仍然有效)。根据The Java™ Tutorials

第一个参数是这个特定的对象实例 方法将被调用。 (如果方法是静态的,第一个参数 应该为空。)

以下显示了一个完整的示例 (Main.java),适用于 static(by class) VS non-static(by instance),另外还有 strong>带参数的方法import必要类,catch异常,还有超类方法示例。

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

class Love {
   protected void Method4() {
        System.out.println("calls super protected method by instance");
    }

   public void Method5() {
        System.out.println("calls super public method by instance");
    }
}

class Main extends Love {

    static void Method2(int y) {
        System.out.println("by class: " + y);
    }

    void Method3(String y) {
        System.out.println(y);
    }

    public static void main(String[] args) {

        String MyVar = "2";
        String MyAnotherVar = "3";
        String MySuperVar = "4";
        String MySuperPublicMethodVar = "5";
        Main m = new Main();

       try {
            Method method = Main.class.getDeclaredMethod("Method" + MyVar, int.class); //by class
            Method anotherMethod = m.getClass().getDeclaredMethod("Method" + MyAnotherVar, String.class); //by instance
            Method superMethod = m.getClass().getSuperclass().getDeclaredMethod("Method" + MySuperVar); //super method by instance, can be protected
            Method superPublicMethod = m.getClass().getMethod("Method" + MySuperPublicMethodVar); //getMethod() require method defined with public, so even though sublcass calls super protected method will not works
            try {
                method.invoke(null, 10000);//by class
                anotherMethod.invoke(m, "by instance"); //by instance
                superMethod.invoke(m); //super method by instance
                superPublicMethod.invoke(m); //super's public method by instance
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }

       } catch (NoSuchMethodException e) {
           throw new RuntimeException(e);
       } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
       }
    }
}

输出:

$ javac Main.java
$ java Main 
by class: 10000
by instance
calls super protected method by instance
calls super public method by instance
$ 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 1970-01-01
    相关资源
    最近更新 更多