Компилирует ли команда java Java-программы?




javac (4)

Большинство сайтов в интернете говорят:

"используйте команду javac для компиляции файла .java . Затем запустите его с помощью команды java "

Но сегодня я попытался запустить программу Java без Java, и я получил странный результат.

Вот содержимое файла с именем hello.java :

public class Myclass {
 public static void main(String[] args){
    System.out.println("hello world");
  }
}

Затем я побежал:

$ javac hello.java

Что дает мне эту ошибку:

hello.java:1: error: class Myclass is public, should be declared in a file named Myclass.java
public class Myclass {
       ^
1 error

Но когда я запускаю его без команды javac , он выполняется без ошибок.

$ java hello.java
hello world

Команда java также компилирует программу? Если да, зачем нам команда javac ?

Версия моего Java:

openjdk version "12.0.2" 2019-07-16
OpenJDK Runtime Environment (build 12.0.2+10)
OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode)

Да, но не так, как вы, вероятно, имеете в виду.

Когда вы используете команду javac для компиляции файла .java в файл .class, на выходе получается нечто, называемое байт-кодом. Байт-код - это машинный код (собственные инструкции) для теоретического ЦП, основанного на спецификации виртуальной машины Java.

Эта спецификация виртуального ЦП является своего рода средним числом типов ЦП, которые были распространены на момент написания спецификации. Из-за этого он близок к множеству разных типов процессоров, что облегчает запуск одних и тех же файлов Java .class на нескольких типах процессоров.

При первом запуске java команда java считывала файл .class и интерпретировала инструкции байт-кода по одной, а затем сопоставляла их с эквивалентной встроенной инструкцией для того процессора, на котором она фактически выполнялась. Это сработало, но не особенно быстро. Для улучшения этой компиляции в JIT была добавлена ​​Java Runtime.

С помощью JIT команда java берет байт-код и снова компилирует его в исходные инструкции для процессора, на котором работает. Современные среды выполнения Java, как правило, начинают интерпретировать байт-код при JIT-компиляции в фоновом режиме и переключаются на скомпилированные нативные инструкции, когда он будет готов, а также профилируют работающее приложение, а затем заново компилируют байт-код с другой оптимизацией, чтобы получить наилучшую возможную производительность.

РЕДАКТИРОВАТЬ (чтобы успокоить избирателей):

Таким образом, в вашем конкретном случае (поскольку вы используете JRE новее, чем v11), код компилируется (как минимум) дважды

  1. Как один файл .java для байт-кода
  2. С помощью JIT-компилятора, поскольку он интерпретирует байт-код (хотя для helloWorld у него может не хватить времени для запуска любого скомпилированного нативного кода)

До Java 11 для запуска вашего кода вы должны сначала скомпилировать его, а затем запустить его. Вот пример:

javac test.java
java test

Начиная с Java 11, вы все еще можете делать javac + java или запускать java отдельно для компиляции и автоматического запуска вашего кода. Обратите внимание, что файл .class не будет создан. Вот пример:

java test.java

Если вы запустите java -help , вы увидите различные разрешенные варианты использования. Вот как это выглядит на моей машине. Последнее - это то, с чем вы столкнулись: java [options] <sourcefile> [args] который будет «выполнять одну программу с исходным файлом».

$ java -help
Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  java [options] <sourcefile> [args]
           (to execute a single source-file program)

ОБНОВИТЬ:

Как отмечает @BillK, ОП также спросил:

зачем нам команда javac?

Причина, по которой нам нужен javac заключается в том, чтобы создавать .class чтобы код можно было создавать, тестировать, распространять, запускать, передавать и т. Д., Как это делается сегодня. Мотивация для JEP 330 состояла в том, чтобы облегчить «ранние этапы изучения Java и при написании небольших служебных программ» без изменения каких-либо других существующих применений.


Эта функция позволяет запускать исходный код Java с одним файлом напрямую без какой-либо компиляции, избегая утомительных шагов, которые ранее требовались для запуска простой программы hello world.

Java 11+ Launch Single-File Source-Code Programs 

Зачем вам это нужно? Если вы вспомните старые времена незадолго до Java SE 11 (JDK 11), скажем, у вас есть исходный файл HelloUniverse.java, который содержит определение класса и статический метод main, который выводится в виде одной строки текста в терминал вроде следующего:

public class HelloUniverse{
      public static void main(String[] args) { 
            System.out.println("Hello InfoQ Universe");
      }
}

Обычно для запуска этого класса сначала нужно скомпилировать его с помощью компилятора Java (javac), что приведет к созданию файла HelloUniverse.class:

$ javac HelloUniverse.java
Then you would use a java virtual machine (interpreter) command to run the resulting class file:

$ java HelloUniverse
Hello InfoQ Universe

Это запускает JVM, загружает класс и выполняет код.

Но что, если вы хотите быстро протестировать кусок кода и хотите поэкспериментировать? Эти два шага в процессе могут показаться немного тяжелыми. В Java SE 11 вы можете запустить один файл исходного кода напрямую, без промежуточной компиляции.


Если вы работаете с Java 11, есть новая функция, которая позволяет выполнять один исходный файл. Компилятор с одним исходным кодом более разнороден с точки зрения имени класса по сравнению с именем файла, поэтому вы можете работать, но не успешно компилировать.

Если вы используете предыдущую версию Java, то ваш текущий hello.java не компилируется из-за ошибок компиляции, особенно вокруг имени класса. Таким образом, абсолютно невозможно, чтобы вызов java hello.java компилировал ваш код, потому что он не компилируется.

Наиболее вероятно, что вы выполняли какой-то ранее скомпилированный код при выполнении команды java.





javac