Groovy方式动态调用静态方法

时间:2009-02-23 09:01:38

标签: groovy

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

Foo."get"(1)
  /* or */
String meth = "get"
Foo."$meth"(1)

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

String clazz = "Foo"
"$clazz".get(1)

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

6 个答案:

答案 0 :(得分:29)

根据Guillaume Laforge对Groovy ML的建议,

("Foo" as Class).get(i)

会得到相同的结果。

我已使用此代码进行了测试:

def name = "java.lang.Integer"
def s = ("$name" as Class).parseInt("10")
println s

答案 1 :(得分:16)

试试这个:

def cl = Class.forName("org.package.Foo")
cl.get(1)

稍微长一点但应该有用。

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

map[name].get(1)

选择其中一个。

[编辑] "$name"是一个GString,因此是一个有效的声明。 "$name".foo()表示“调用类foo()的方法GString

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

Class.forName("com.acme.MyClass", true, Thread.currentThread().contextClassLoader)

Class.forName("com.acme.MyClass", true, getClass().classLoader)

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

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

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

    ... test ...
} finally {
    Thread.currentThread().contextClassLoader = orig
}

答案 2 :(得分:3)

增加Chanwit的答案,说明创建实例:

def dateClass = 'java.util.Date' as Class
def date = dateClass.newInstance()
println date

答案 3 :(得分:2)

这是另一种方式

import org.codehaus.groovy.grails.commons.ApplicationHolder as AH

def target = application.domainClasses.find{it.name == 'ClassName'}
target.clazz.invokeMethod("Method",args)

使用此功能,您无需指定包名称。如果你在两个不同的包中有相同的类名,请注意。

答案 4 :(得分:1)

Groovy ML上的Melix指出我在动态类方法调用的“正确”方向上一段时间,非常有用:

// define in script (not object) scope  
def loader = this.getClass().getClassLoader()

// place this in some MetaUtils class, invoked on app startup  
String.metaClass.toClass = {  
    def classPath = getPath(delegate) // your method logic to determine 'path.to.class'
    Class.forName(classPath, true, this.loader)  
}

// then, anywhere in your app  
"Foo".toClass().bar()

您可以创建另一个字符串metaClass方法来创建实例,并根据需要进行重构:

String.metaClass.toObject = {  
    def classPath = getPath(delegate)  
    Class.forName(classPath, true, this.loader).newInstance()  
}

Groovy非常有趣; - )

答案 5 :(得分:1)

我正在运行1.8.8版本的groovy ......简单的例子可以运行。

Import my.Foo
def myFx="myMethodToCall"
def myArg = 12

Foo."$myFx"(myArg)

按预期和期望调用Foo.myMethodToCall(12)。我不知道是否一直如此。