您需要注意一些事项。当您创建一个包含以下内容的脚本(我们称之为someScript.groovy)时:
#!groovy
println "Test"
println 21 + 21
它被编译为以下类:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
public class someScript extends Script {
public someScript() {
}
public someScript(Binding context) {
super(context);
}
public static void main(String... args) {
InvokerHelper.runScript(someScript.class, args);
}
public Object run() {
((someScript)this).println("Test");
Object var10000 = null;
((someScript)this).println(21 + 21);
return null;
}
}
如您所见,Groovy 脚本的主体在生成的类中表示为方法run()。当我们向这个脚本添加一个类时,假设您的问题中的 Example 类,run() 方法的主体根本不会改变 - 该类被编译为一个 Example.class 字节码文件,就是这样:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Closure;
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.GeneratedClosure;
public class Example implements GroovyObject {
public Example() {
MetaClass var1 = this.$getStaticMetaClass();
this.metaClass = var1;
}
public static void main(String... args) {
class _main_closure1 extends Closure implements GeneratedClosure {
public _main_closure1(Object _outerInstance, Object _thisObject) {
super(_outerInstance, _thisObject);
}
public Object doCall(Object it) {
DefaultGroovyMethods.println(Example.class, "Hello World");
return null;
}
public Object call(Object args) {
return this.doCall(args);
}
public Object call() {
return this.doCall((Object)null);
}
public Object doCall() {
return this.doCall((Object)null);
}
}
Closure clos = new _main_closure1(Example.class, Example.class);
clos.call();
}
}
当我们运行 Groovy 编译器来编译 someScript.groovy (groovyc someScript.groovy) 并列出生成的类时,我们会看到如下内容:
ls -lh *.class
-rw-rw-r--. 1 wololock wololock 2,0K 12-07 10:26 Example.class
-rw-rw-r--. 1 wololock wololock 1,6K 12-07 10:26 'Example$_main_closure1.class'
-rw-rw-r--. 1 wololock wololock 1,4K 12-07 10:26 someScript.class
注意:这个Example$_main_closure1.class 表示Example.main() 方法中使用的闭包
现在,让我们看看如果我们从 someScript.groovy 文件中注释(或删除)println 语句并编译它会发生什么:
someScript.groovy
#!groovy
class Example {
static void main(String[] args) {
def clos = {println "Hello World"};
clos.call();
}
}
//println "Test"
//
//println 21 + 21
编译时间:
> groovyc someScript.groovy
> ls -lh *.class
-rw-rw-r--. 1 wololock wololock 2,0K 12-07 10:31 Example.class
-rw-rw-r--. 1 wololock wololock 1,6K 12-07 10:31 'Example$_main_closure1.class'
如您所见,没有生成someScript.class 类文件。发生这种情况是因为我们刚刚编译的脚本文件不包含任何正文,但它里面有Example 类。当您运行这样的脚本时,Groovy 会尝试定位第一个静态 main() 方法来执行它 - 这就是运行以下脚本会产生 Hello World 输出的原因:
> groovy someScript.groovy
Hello World
让我们更进一步,在 someScript.groovy 文件的顶部添加另一个类:
someScript.groovy
#!groovy
class Foo {
static void main(String[] args) {
println "Bar"
}
}
class Example {
static void main(String[] args) {
def clos = {println "Hello World"};
clos.call();
}
}
//println "Test"
//
//println 21 + 21
脚本的主体仍然被注释掉。让我们编译看看生成了哪些类文件:
> groovyc someScript.groovy
> ls -lh *.class
-rw-rw-r--. 1 wololock wololock 2,0K 12-07 10:35 Example.class
-rw-rw-r--. 1 wololock wololock 1,6K 12-07 10:35 'Example$_main_closure1.class'
-rw-rw-r--. 1 wololock wololock 1,8K 12-07 10:35 Foo.class
正如预期的那样,我们可以看到 3 个类文件。让我们看看如果我们使用groovy 命令运行脚本会发生什么:
> groovy someScript.groovy
Bar
现在你可以看到Foo.main() 方法被执行了,因为Groovy 将该方法定位在脚本文件的顶部,并且假设这是我们要运行的主要方法。
让我们用包含两个类和脚本主体的示例来完成这个:
someScript.groovy
#!groovy
class Foo {
static void main(String[] args) {
println "Bar"
}
}
class Example {
static void main(String[] args) {
def clos = {println "Hello World"};
clos.call();
}
}
println "Test"
println 21 + 21
编译时间:
> groovyc someScript.groovy
> ls -lh *.class
-rw-rw-r--. 1 wololock wololock 2,0K 12-07 10:39 Example.class
-rw-rw-r--. 1 wololock wololock 1,6K 12-07 10:39 'Example$_main_closure1.class'
-rw-rw-r--. 1 wololock wololock 1,8K 12-07 10:39 Foo.class
-rw-rw-r--. 1 wololock wololock 1,4K 12-07 10:39 someScript.class
这次生成了一个类someScript,因为脚本主体不为空。最后看一下生成的someScript.class文件:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
public class someScript extends Script {
public someScript() {
}
public someScript(Binding context) {
super(context);
}
public static void main(String... args) {
InvokerHelper.runScript(someScript.class, args);
}
public Object run() {
((someScript)this).println("Test");
Object var10000 = null;
((someScript)this).println(21 + 21);
return null;
}
}
如您所见,与我们的第一个示例相比(当脚本中没有类,但只有两个 println 语句时),它并没有改变,所以除了运行 someScript.run() 方法之外,我们不能指望其他任何事情发生.让我们运行脚本:
> groovy someScript.groovy
Test
42
结论
- 当您创建 Groovy 脚本时,它的主体会被移动并编译为
scriptName.run() 方法,然后会被执行。
- 如果你将一个带有
main() 方法的类添加到Groovy 脚本并保留脚本主体,添加的类main() 方法将不会被执行——它只会编译类,你可以在你的脚本正文(如果需要)。
- 如果你将一个带有
main() 方法的类添加到一个Groovy 脚本并且你没有放置任何脚本主体(任何在类之外的语句/表达式),那么Groovy 会搜索第一个静态main() 方法,并且它执行它。