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

标签 groovy

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 in Example.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/

相关文章:

groovy - 在 SOAPUI 中将参数从 Java 传递到 Groovy

json - Groovy JsonSlurper 和嵌套映射

groovy - 是否有与Scala的文字标识符等效的Groovy?

list - Groovy列表移位和不移位

variables - Jenkins Groovy 并行变量不工作

groovy - 带有Groovy API的Elasticsearch Bool过滤器

jquery - 如何在 Grails Controller 中解析 JSON

hibernate - 使用Hibernate进行复杂查询的问题

html - 您如何解析网页并提取所有 href 链接?

grails - 在产生的 war 中grails.xml中错误的路径