Groovy 版本:2.4.5 JVM:1.8.0_151 供应商:Oracle Corporation 操作系统:Linux
我已经尝试了两个版本的 Groovy 程序。如果我在程序中没有其他内容(例如,没有'println“Test”'),则运行“Example”类。
如果我有“println”语句,为什么 Example 类不运行?
class Example {
static void main(String[] args) {
def clos = {println "Hello World"};
clos.call();
}
}
println "Test"
我希望上面的程序在运行时打印这个:
Hello World
Test
为什么类在它外面有另一行时不执行?
最佳答案
您需要了解一些事情。当您创建具有以下内容的脚本(我们称之为 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
NOTE: this
Example$_main_closure1.class
represents a closure used inExample.main()
method
现在,让我们看看如果我们从 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()
方法,并执行它。
关于groovy - 如果类外有一行代码,为什么 Groovy 不执行程序中的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53662303/