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

146

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

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

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

Вот содержимое файла с именем 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)
Milad
источник
11
Какую версию вы используете? Я думаю, что они представили консоль Java в Java 9, и это может быть то, что вы испытали.
Матье
6
Вам необходимо сопоставить имя класса с именем файла - это стандарт Java. Просто измените имя файла на Myclass.javaи затем из командной строки скомпилируйте его следующим образом, javac Myclass.javaа затем запустите его следующим образом java Myclass.
unnsse
6
да, до javacсих пор используются для компиляции , если вы не хотите , чтобы развернуть исходный код, или у вас есть более чем один файл ( документация по java: для варианта исходного файла используется только для запуска одной программы исходного файла.)
user85421
@Matthieu выводит "java -version": openjdk version "12.0.2" 2019-07-16 Среда выполнения OpenJDK (сборка 12.0.2 + 10) Виртуальная машина OpenJDK 64-Bit Server (сборка 12.0.2 + 10, смешанная режим)
milad
1
@Milad - что происходит, это - javacкомпилирует исходный код Java в специфический интерпретируемый байт-код JVM, и javaкоманда загружает его в ClassLoader JVM.
unnsse

Ответы:

189

До 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 и при написании небольших служебных программ» без изменения каких-либо других существующих применений.

Каан
источник
49
представленный в Java 11: Что нового, и / или JEP 330: Запуск
однофайловых
спасибо @CarlosHeuberger за дополнительную информацию. Я сделал небольшой редактировать в моем ответе , чтобы отразить , что он был введен в Java 11
Каан
7
@Spikatrix это Java 8 (они упали 1.в 1.8в новых версиях)
Muru
1
Вы не ответили на вопрос, почему нам все еще нужен javac - я думаю, что java работает только с тем файлом, который вы ему предоставили, и предварительно скомпилированными файлами. Я считаю, что вы должны скомпилировать все остальные файлы, которые вы хотите использовать, из файла, который вы вызываете.
Билл К
2
В этом ответе не указывается, почему этот новый метод не приводит к ошибке «имя файла или ошибка имени класса», о которой сообщает javac.
Себрокм
52

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

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

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

Evan
источник
спасибо, версия Java: openjdk версия "12.0.2" 2019-07-16 Среда выполнения OpenJDK (сборка 12.0.2 + 10) Виртуальная 64-битная серверная OpenJDK (сборка 12.0.2 + 10, смешанный режим)
сентябрь
5
проверить использование режима исходного файла для запуска однофайловых программ с исходным кодом : «Компилятор не применяет необязательное ограничение, определенное в конце JLS 7.6, что тип в именованном пакете должен существовать в файле с именем состоит из имени типа, за которым следует расширение .java. "
user85421
2
API сценариев Java и запуск программы Java с одним файлом исходного кода ( JEP 330 ) - это две совершенно разные и совершенно не связанные друг с другом вещи.
Дэвид Конрад
@DavidConrad, обновлено словоблудие соответственно. Спасибо.
Эван
Цените ввод, @TJCrowder. Но я уверен, что хотел написать все как есть. Кроме того, второе определение в ваших ссылках: Разнородные средства, включая широкий спектр разных вещей.
Эван
6

Чтобы ответить, почему дается эта ошибка, имя класса для файла должно совпадать с именем файла basename.

У вас есть два варианта, чтобы этот код работал для традиционного javac; javaпоследовательность:

  1. Переименуйте класс в public class Helloили

  2. Переименовать hello.javaв myclass.java.

javaИнтерпретатор Java 11 не навязывает это требование. Класс, который содержит, mainможет иметь любое имя, если это первый класс в файле. Это было главным образом предназначено, чтобы облегчить процесс обучения для начинающих, и позволить "сценарии Java" с Шебангом ( ссылка ).

СС Энн
источник
5

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

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

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

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

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

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

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

  1. Как один файл .java для байт-кода
  2. Через JIT-компилятор, поскольку он интерпретирует байт-код (хотя для helloWorld у него может не хватить времени для запуска какого-либо скомпилированного нативного кода)
hardillb
источник
7
Это не отвечает на вопрос.
Дэвид Конрад
2
@DavidConrad Но это так! Ответ на вопрос «Компилирует ли команда java Java-программы?» это громкое «да» по причинам, которые здесь приводит hardlib: он будет скомпилировать байт-код с нативными инструкциями точно в срок (для нетривиальных программ со стандартными настройками).
Питер - Восстановить Монику
Обязательна ли сейчас компиляция? Исторически Java-байт-код можно было интерпретировать; JIT-компиляция была необязательной.
MSalters
JIT включен по умолчанию в эти дни (на очень долгое время), как показывают mixed-modeвыходные данные версии
hardillb