如果类之外有一行代码,为什么Groovy不执行程序中的类?

Jer*_*moe 2 groovy

Groovy版本:2.4.5 JVM:1.8.0_151供应商:Oracle Corporation操作系统:Linux

我已经尝试了两个Groovy程序版本。如果程序中没有其他内容,则运行“ Example”类(例如,没有“ println“ Test”“)。

如果我有一个“ println”语句,为什么Example类不能运行?

class Example {
   static void main(String[] args) {
      def clos = {println "Hello World"};
      clos.call();
   }
}

println "Test"
Run Code Online (Sandbox Code Playgroud)

我希望上面的程序在运行时将其打印出来:

你好,世界

测试

当类外还有另一行时,为什么类不执行?

Szy*_*iak 7

您需要注意一些事情。当您创建someScript.groovy具有以下内容的脚本(我们称之为)时:

#!groovy

println "Test"

println 21 + 21
Run Code Online (Sandbox Code Playgroud)

它被编译为以下类:

//
// 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,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();
    }
}
Run Code Online (Sandbox Code Playgroud)

当我们运行Groovy编译器来编译someScript.groovygroovyc 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
Run Code Online (Sandbox Code Playgroud)

注意:这Example$_main_closure1.class表示Example.main()方法中使用的闭包

现在,让我们看看如果printlnsomeScript.groovy文件中注释(或删除)语句并对其进行编译会发生什么:

someScript.groovy

#!groovy

class Example {
    static void main(String[] args) {
        def clos = {println "Hello World"};
        clos.call();
    }
}

//println "Test"
//
//println 21 + 21
Run Code Online (Sandbox Code Playgroud)

编译时间:

> 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'
Run Code Online (Sandbox Code Playgroud)

如您所见,没有someScript.class生成任何类文件。发生这种情况是因为我们刚刚编译的脚本文件不包含任何主体,但其中包含Example类。当您运行这样的脚本时,Groovy会尝试找到第一个静态main()方法来执行它-这就是为什么运行以下脚本会产生Hello World输出的原因:

> groovy someScript.groovy 
Hello World
Run Code Online (Sandbox Code Playgroud)

让我们进一步,在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
Run Code Online (Sandbox Code Playgroud)

该脚本的正文仍被注释掉。让我们进行编译并查看生成了哪些类文件:

> 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
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,我们可以看到3个类文件。让我们看看如果使用groovy命令运行脚本会发生什么:

> groovy someScript.groovy                             
Bar
Run Code Online (Sandbox Code Playgroud)

现在您可以看到该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
Run Code Online (Sandbox Code Playgroud)

编译时间:

> 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
Run Code Online (Sandbox Code Playgroud)

这次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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,与我们的第一个示例相比(当脚本内没有类,只有两个println语句时),它没有改变,所以我们除了运行someScript.run()方法之外别无他法。让我们运行脚本:

> groovy someScript.groovy
Test
42
Run Code Online (Sandbox Code Playgroud)

结论

  • 创建Groovy脚本时,其主体将被移动并编译为scriptName.run()方法,并被执行。
  • 如果main()在Groovy脚本中添加带有方法的类并保留脚本主体,则添加的类main()方法将不会执行-它仅编译该类,并且可以根据需要在脚本主体中显式使用它。
  • 如果您将带有main()方法的类添加到Groovy脚本中,并且没有放置任何脚本主体(类之外的任何语句/表达式),则Groovy将搜索第一个静态main()方法,然后执行该方法。