我正在研究动态修改Java应用程序行为的方法(具体来说,我正在尝试制作一个Minecraft mod,允许用户通过编写代码来修改他们找到的对象的行为,而无需重新启动游戏我偶然发现了Groovy。我的问题是:是否有可能以他们“共享”对象的方式集成Java和Groovy? (我正在考虑使用一组特定的实际Groovy代码类,以便您可以在运行时更改代码,类似于您在任何Smalltalk实现中可以执行的操作)
答案 0 :(得分:4)
看看Integrating Groovy in a Java Application。它显示了如何使用groovy.lang.Binding
从Java应用程序内部运行Groovy脚本并在它们之间共享数据的示例。
答案 1 :(得分:3)
多么酷的主意!
<强> 1。 Groovy: Java和Groovy可以共享对象并来回调用。实现Java接口的Groovy类很容易从Java调用。 (还有其他方法,比如从Java调用groovyObject.invokeMethod("methodName", args)
。)对于JVM语言,Groovy与Java有最紧密的集成。 Java程序员也很容易学习,因为它与Java共享很多东西。
本书Groovy in Action有一章“集成Groovy”,解释和比较这些方法(比the reference docs更详细):GroovyShell,GroovyScriptEngine,GroovyClassLoader,Spring集成和JSR-223 ScriptEngineManager。 GroovyClassLoader是最有能力的选择。
然而,虽然很容易在运行时编译和加载Groovy代码,但我很困惑如何改变现有对象实例的行为(缺少下面关于热交换的注释< / em>的)。 (这可能取决于类是重写Java接口还是子类化Java类。)请考虑:
class G implements Runnable {
void run() { println 'Groovy' }
}
g = new G()
g.run()
这会打印Groovy
。现在重新定义班级:
class G implements Runnable {
void run() { println 'Groovy!' }
}
g1 = new G()
g.run()
g1.run()
打印
Groovy
Groovy!
现在使用元类在运行时更改方法:
G.metaClass.run = { println 'Groovy!!!' }
g2 = new G()
g.run()
g1.run()
g2.run()
打印
Groovy
Groovy!
Groovy!
如果我们从这些类定义中省略implements Runnable
,那么最后一步将打印
Groovy
Groovy!
Groovy!!!
但是我们的类确实实现了Runnable,现在执行:
G.metaClass.run = { println 'Very Groovy!!!' }
g3 = new G()
g.run()
g1.run()
g2.run()
g3.run()
打印:
Groovy
Groovy!
Very Groovy!!!
Very Groovy!!!
解决方法是在类变量中保存的闭包中实现方法。
<强> 2。热交换:如果要点是在运行时为具有现有实例的类重新定义方法体,那么您只需在IDE的调试器中运行并使用热交换。
E.g。对于IntelliJ,这里是Java和Groovy代码的instructions to configure hot swapping。
第3。扩展热插拔:如果您还希望能够在运行时添加/删除方法和实例变量,请通过DCEVM(JetBrains article on extended hot swapping)查看此Dynamic Code Evolution VM。
上的热插拔代码答案 2 :(得分:1)
我不确定使用Groovy可以在不编译的情况下完成的事情。你可以做到,但是#34;脚本&#34; Groovy的方面不会帮助你。我希望让玩家编写javascript并使用Java ScriptEngine
。见这里:http://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_guide/
答案 3 :(得分:1)
是的,你可以做到这一点。例如,你有一些用java编写的东西,它使用一些来自let spring的对象。所以现在你能做的是:
基本上,在执行Java代码的那一刻,他将获得一个包装对象,并在运行时进行一些更改。
如果您正在尝试做什么,请告诉我,我可以为您编写一些示例代码。