Groovy方式动态调用静态方法

Joh*_*ner 27 groovy

我知道在Groovy中,您可以使用字符串在类/对象上调用方法.例如:

Foo."get"(1)
  /* or */
String meth = "get"
Foo."$meth"(1)
Run Code Online (Sandbox Code Playgroud)

有没有办法在课堂上这样做?我将类的名称作为字符串,并希望能够动态调用该类.例如,希望做类似的事情:

String clazz = "Foo"
"$clazz".get(1)
Run Code Online (Sandbox Code Playgroud)

我想我错过了一些非常明显的东西,但我无法弄明白.

cha*_*wit 29

正如Guillaume Laforge对Groovy ML的建议,

("Foo" as Class).get(i)
Run Code Online (Sandbox Code Playgroud)

会给出相同的结果.

我用这段代码测试过:

def name = "java.lang.Integer"
def s = ("$name" as Class).parseInt("10")
println s
Run Code Online (Sandbox Code Playgroud)

  • 这适用于grails 1.3.4 grailsApplication.classLoader.loadClass(name); (3认同)

Aar*_*lla 16

试试这个:

def cl = Class.forName("org.package.Foo")
cl.get(1)
Run Code Online (Sandbox Code Playgroud)

稍微长一点,但应该工作.

如果你想为静态方法创建类似"switch"的代码,我建议实例化类(即使它们只有静态方法)并将实例保存在地图中.然后你可以使用

map[name].get(1)
Run Code Online (Sandbox Code Playgroud)

选择其中一个.

[编辑] "$name"GString一个有效的声明."$name".foo()意思是"调用foo()类的方法GString.

[EDIT2]使用Web容器(如Grails)时,必须指定类加载器.有两种选择:

Class.forName("com.acme.MyClass", true, Thread.currentThread().contextClassLoader)
Run Code Online (Sandbox Code Playgroud)

要么

Class.forName("com.acme.MyClass", true, getClass().classLoader)
Run Code Online (Sandbox Code Playgroud)

第一个选项仅适用于Web上下文,第二个选项也适用于单元测试.这取决于您通常可以使用与调用的类相同的类加载器forName().

如果您遇到问题,请使用第一个选项并设置contextClassLoader单元测试:

def orig = Thread.currentThread().contextClassLoader
try {
    Thread.currentThread().contextClassLoader = getClass().classLoader

    ... test ...
} finally {
    Thread.currentThread().contextClassLoader = orig
}
Run Code Online (Sandbox Code Playgroud)