Основной метод среды выполнения JavaFX - PullRequest
0 голосов
/ 21 сентября 2018

Hello World-Tutorial JavaFX гласит:

Метод main () не требуется для приложений JavaFX, когда файл JAR для приложения создается с помощью JavaFXУтилита Packager, которая встраивает модуль запуска JavaFX в файл JAR.Тем не менее, полезно включить метод main (), чтобы можно было запускать файлы JAR, созданные без JavaFX Launcher, например, при использовании IDE, в которой инструменты JavaFX не полностью интегрированы.Кроме того, приложения Swing, которые встраивают код JavaFX, требуют метода main ().

Я попробовал это, и это правда, я могу запустить свое приложение без main метода.

Однакокогда я объявляю метод main вызовом launch из класса Application, программа все еще работает.В документации Application говорится, что среда выполнения JavaFX создает экземпляр класса Application и вызывает метод init.

Но как запускается среда выполнения JavaFX?Я имею в виду, что где-то должен быть метод main, чтобы все началось.Поэтому мне интересно, если я сам объявлю main метод, разве нет двух из них?

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Меня всегда интересовало, как Java запускает приложения JavaFX, поэтому я решил отладить этот процесс.Некоторые вещи перед остальным ответом:

  • Я сделал отладку с JDK-10 для автономного настольного приложения.Некоторые быстрые взгляды на исходный код JDK-11 показывают, что процесс не изменился между версиями.
  • Когда я использую Application, я имею в виду класс javafx.application.Application.
  • Когда яиспользовать "main метод" Я имею в виду метод public static void main(String[] args).Аналогично, «основной класс» относится к классу, содержащему метод main.
  • Все ссылки на исходный код указывают на репозиторий OpenJDK Mercurial.
  • Практически все это является подробностью реализации иможет быть изменено без предварительного уведомления.

Сводка

Если при запуске приложения JavaFX основной класс является подклассом Application, то средство запуска Java использует это собственный, внутренний основной класс .Этот внутренний класс отвечает за инициализацию инструментария JavaFX.После инициализации инструментария может произойти одно из двух:

  1. Подкласс Application имеет метод a main.
    • В этом случае некоторый внутренний код JavaFX вызывает метод main.Теперь разработчики обязаны завершить запуск приложения с помощью Application.launch.
  2. . Подкласс Application не имеет a main метода.
    • В этом случае тот же внутренний код JavaFX запускает само приложение.Первый случай в конечном итоге заканчивается в том же месте, что и этот случай.

По сути, любой метод main, объявленный в подклассах Application, не является "нормальным" mainметоды.Представьте себе такое поведение следующим образом:

  • Внутренний main метод действует как точка входа для приложения Java - так же, как все "нормальные" main методы
  • The *Метод 1062 * subclass 'main служит дополнительной точкой входа для приложения JavaFX, где инструментарий JavaFX уже инициализирован.

Подробный ответ

Во-первых, этодело не в том, что вы "переопределяете" метод main класса Application;класс Application не имеет метода main.На самом деле происходит то, что Java использует свой собственный главный класс, когда объявленный основной класс приложения является подклассом Application.Для потомков главный класс может быть объявлен с помощью одного из следующих:

  • Указание его в командной строке (файл): java -cp <classpath> foo.Main
  • Указание его в командной строке (модуль): java -p <modulepath> -m foo/foo.Main
  • Указание его в манифесте JAR: Main-Class: foo.Main
  • (Другой способ, которым я забыл?)

Шаги

Эти шаги предполагают приложение JavaFX.Большая часть этого не происходит при запуске «обычного» Java-приложения.

Шаг 1. Загрузка основного класса

Внутренний класс LauncherHelper проверяет и загружает основной класс с помощьюметод с именем checkAndLoadMain.Этот метод отвечает за разрешение основного класса в зависимости от того, как был объявлен основной класс (описано выше).После обнаружения этот метод проверяет, является ли основной класс подклассом Application.Если это так, тогда основной класс заменяется на статический внутренний класс: LauncherHelper$FXHelper.Затем выполняется некоторая проверка и Class возвращается, я полагаю, к собственному коду.

Соответствующий код:

Шаг 2: вызвать mainМетод

После того, как основной класс найден, загружен и проверен, он вызывается из (я предполагаю) собственного кода.Поскольку мы говорим о приложении JavaFX, основным классом теперь является LauncherHelper$FXHelper.Метод main этого класса выполняет одну простую вещь: вызывает внутренний код JavaFX с помощью отражения.

Соответствующий код:

Шаг 3: Предварительный запуск JavaFX

Код, вызываемый на шаге 2, находится внутри класса с именем LauncherImpl;в частности, метод launchApplication(String,String,String[]).Похоже, что этот метод делает то же самое, что и LauncherHelper.checkAndLoadMain, за исключением более специфичного для JavaFX.

Я считаю, что этот метод похож на checkAndLoadMain, потому что метод checkAndLoadMain проверяет класс FXHelper, который, очевидно, является допустимым,Однако launchApplication необходимо проверить подкласс Application.

Соответствующий код:

Шаг 4. Запуск JavaFX

Следующий вызываемый метод - launchApplicationWithArgs(ModuleAccess,String,String,String[]).Этот метод отвечает за запуск инструментария JavaFX.После этого он загружает подкласс Application и, если имеется, подкласс Preloader как фактические экземпляры Class.Это делается в потоке приложений JavaFX , но затем возвращается в основной поток.

Затем код выбирает один из двух путей в зависимости от наличия метода main в Application подкласс:

  1. A main метод существует: Перейдите к шагу 5.
  2. A main метод не существует: Перейдите к шагу 6 (запустите приложение напрямую)

Соответствующий код:

Шаг 5: Вызвать main Метод Application Подкласс (Необязательно)

Если в подклассе Application есть метод main, он вызывается с помощью отражения.В настоящее время разработчик обязан продолжить процедуру запуска с помощью вызова Application.launch.Существуют две перегрузки метода launch:

  1. Application.launch(String...)
  2. Application.launch(Class,String)

Единственное отличие состоит в том, что первый вариант используетвызов Class в качестве подкласса JavaFX Application.Оба в итоге звонят LauncherImpl.launchApplication(Class,String[]).Этот последний метод просто загружает Class из Preloader, если необходимо, и затем переходит к следующему шагу.

Соответствующий код:

Шаг 6: Завершить запуск приложения JavaFX

Теперь мы используем метод LauncherImpl.launchApplication(Class,Class,String[]).Этот метод выполняет две простые вещи:

  1. Создание и запуск потока JavaFX-Launcher , который вызывает другой метод
    • LauncherImpl.launchApplication1(Class,Class,String[])
  2. Паркуйте основной поток (или любой другой поток с именем Application.launch) в CountDownLatch до тех пор, пока не выйдет инструментарий JavaFX.

Метод launchApplication1 запустит инструментарий JavaFX, если онеще не было начато.Затем он продолжает реализацию стандартного жизненного цикла JavaFX.Это включает в себя создание классов Application и, если они есть, Preloader, а затем вызов методов init() и start(Stage) в подходящее время в соответствующих потоках.Этот жизненный цикл является публично определенным поведением;практически все остальное, упомянутое здесь, является подробностями реализации.

Соответствующий код:

Non- Application MainКласс

Существует еще один способ запуска приложений JavaFX, в котором основной класс не является подклассом Application, например:

// main class
public class Main {

    public static void main(String[] args) {
        Application.launch(App.class, args);
    }

}

// JavaFX Application class
public class App extends Application {

    @Override 
    public void start(Stage primaryStage) throws Exception {
        // setup and show primaryStage
    }

}

Поскольку Main не является подклассом Application изменение на FXHelper на шаге 1 не происходит.Это также означает, что шаги 2-5 не выполняются автоматически.Вместо этого вызов Application.launch в Main запускает этот процесс на последнем шаге: 6. Вот почему метод launchApplication1 также пытается запустить инструментарий JavaFX, так как он не был бы запущен в этом сценарии.

0 голосов
/ 21 сентября 2018

Один из возможных ответов, вероятно, заключается в том, что существует метод main, объявленный в Application.И если другой класс, который расширяется от Application, имеет свой собственный метод main, код все равно будет действительным, а метод main Application будет игнорироваться ::

class Main extends OtherMain {
    public Main(String text) {
        System.out.println(text);
    }

    /* If this method is removed, the main-method is called from OtherMain */
    public static void main(String[] args) {
        new Main("Called from Main-Class");
    }
}

class OtherMain {
    public static void main(String[] args) {
        new Main("Called from Other-Main-Class");
    }
}

Имеет ли это смысл?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...