Почему Groovy не выполняет класс в программе, если за пределами класса есть строка кода? - PullRequest
0 голосов
/ 07 декабря 2018

Groovy Версия: 2.4.5 JVM: 1.8.0_151 Поставщик: Oracle Corporation ОС: Linux

Я пробовал две версии моей программы Groovy.Класс «Пример» запускается, если у меня больше ничего нет в программе (например, нет «println« Test »»).

Почему класс Example не запускается, если у меня есть оператор "println"?

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

println "Test"

Я ожидаю, что вышеприведенная программа напечатает его при запуске:

Hello World

Тест

Почему класс не выполняется, если за ним есть другая строка?

1 Ответ

0 голосов
/ 07 декабря 2018

Вы должны знать о нескольких вещах.Когда вы создаете скрипт (назовем его 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() методе

Теперь давайте посмотрим, что произойдет, если мы закомментируем (или удалим) операторы println из файла someScript.groovy имы компилируем его:

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'

Как видите, * 1040 нет* файл класса создан.Это происходит потому, что файл скрипта, который мы только что скомпилировали, не содержит никакого тела, но внутри него есть класс 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() метод, и он выполняет его.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...