首页 文章

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

提问于
浏览
1

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

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

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

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

println "Test"

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

Hello World Test

为什么当它外面有另一行时,类不会执行?

1 回答

  • 4

    你需要注意一些事情 . 当您使用以下内容创建脚本(让我们称之为 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.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
    

    注意:此示例$ _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;
        }
    }
    

    正如你所看到的那样,除了运行 someScript.run() 方法之外别无其他 . 我们来运行脚本:

    > groovy someScript.groovy
    Test
    42
    

    结论

    • 当您创建一个Groovy脚本时,它的主体被移动并编译为 scriptName.run() 方法,并且它被执行 .

    • 如果您将一个带有 main() 方法的类添加到Groovy脚本并保留脚本体,则添加的类 main() 方法将不会被执行 - 它只编译该类,并且您可以在脚本体中显式使用它(如果需要) .

    • 如果您将一个带有 main() 方法的类添加到Groovy脚本中并且您没有放置任何脚本体(类外的任何语句/表达式),那么Groovy会搜索第一个静态 main() 方法,并执行它 .

相关问题