{"id":14275,"url":"\/distributions\/14275\/click?bit=1&hash=bccbaeb320d3784aa2d1badbee38ca8d11406e8938daaca7e74be177682eb28b","title":"\u041d\u0430 \u0447\u0451\u043c \u0437\u0430\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0434\u0430\u0432\u0446\u044b \u0430\u0432\u0442\u043e?","buttonText":"\u0423\u0437\u043d\u0430\u0442\u044c","imageUuid":"f72066c6-8459-501b-aea6-770cd3ac60a6"}

Компиляция и запуск Java-программ (часть 4)

В прошлой публикации мы установили и настроили Sublime Text в качестве редактора для написания кода на Java. Из этой статьи вы узнаете: о компиляции и запуске Java-программ из консоли; как выводить в консоль корректный русский текст; способ отображения байт-кода.

Введение

На первых порах начинающему программисту очень важно научиться выполнять необходимые действия минимальными средствами, чтобы:

  • Иметь представление, что происходит «под капотом»
  • Не быть зависимым от среды разработки
  • Не превратиться в специалиста по нажиманию кнопок в инструментах для профессионалов
  • Не оказаться беспомощным за их пределами

Вам сейчас необходимо набить как можно больше шишек, находясь в спартанских условиях, которые закалят и научат самостоятельно и оперативно решать возникающие проблемы. Это придаст уверенности и повысит вашу экспертность.

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

Компилировать и запускать программы на первых порах мы будем из консоли. Это важный навык, который используется программистами повсеместно.

1. Компиляция

Откройте в Sublime Text файл MyFirstApp.java, а затем запустите терминал с помощью горячих клавиш (у меня Ctrl + Alt + T), настроенных в прошлой статье. Обязательно проверьте, что терминал запустился в папке открытого файла.

Для компиляции воспользуемся уже знакомой утилитой javac (java compiler, компилятор java). Она нужна для преобразования Java-кода в язык виртуальной машины (байт-код).

В терминале пишем команду javac MyFirstApp.java:

Отсутствие каких-либо сообщений свидетельствует о том, что компилятор не нашел ошибок в нашем коде. Результатом его работы стал файл MyFirstApp.class.

2. Запуск

Как мы уже знаем, MyFirstApp.class содержит байт-код. Для его исполнения воспользуемся утилитой java. Именно она стартует JVM, которая, в свою очередь, запустит класс MyFirstApp.

Пишем java MyFirstApp:

Программа отработала верно, выведя в консоль WORA.

Обратите внимание, что необходимо указать не имя файла MyFirstApp.class, а имя класса. При этом писать какое-либо расширение не нужно. Утилита java принимает в качестве параметра именно имя класса, а не имя файла, где он находится.

3. Вывод байт-кода

Мы уже не первый раз упоминаем про байт-код, но до сих пор в глаза его не видели. Исправим эту ситуацию.

Для отображения (декомпиляции) байт-кода класса необходимо в консоли написать команду javap -c MyFirstApp.class:

Как правило, умение читать и понимать байт-код, вносить в него изменения для рядовых Java-разработчиков обычно не требуется — это очень специфические знания. Так что долго не сидите на этой теме.

Если обобщить все этапы, которые проходит программа перед запуском, то схематично их можно отобразить в виде схемы:

4. Запуск однофайловых программ

Чтобы посмотреть, как работает программа, необходимо выполнить два действия: компиляцию и запуск. Если эти шаги требуется исполнять часто, то данный процесс рано или поздно надоест. Хотелось бы его упростить.

Начиная с Java 11, однофайловые программы можно запускать не используя явно этап компиляции.

Удалите из папки class-файл, чтобы все было честно. И запустите программу без компиляции в явном виде, написав java MyFirstApp.java:

Мы только что запустили (и скомпилировали) файл с java-кодом без использования команды javac. При этом исходный код, в любом случае, компилируется в памяти (без создания на диске class-файла), а затем исполняется JVM.

Эта функция ограничена кодом, который хранится в одном файле. Она не сработает для программ, состоящих из двух и более файлов (но и в данном направлении уже ведутся определенные работы).

Теперь, когда вы умеете компилировать и запускать программу, можете поэкспериментировать с кодом MyFirstApp.java, внося в него изменения и смотреть, какие ошибки выдает компилятор.

5. Вывод кириллицы на консоль

Если вы используете Linux или macOS, то дальше можете не читать, т. к. ниже описаны проблемы и их решения для Windows. У вас таких проблем не будет!

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

Внесем исправления в код, написав: «Написано однажды, работает везде», и запустим…

> java MyFirstApp.java Р?апиС?Р°Р?Р? Р?Р?Р?Р°Р?Р?С?, С?Р°Р?Р?С?Р°Р?С? Р?Р?Р·Р?Р?

Что-то пошло не так и вместо русского текста отобразились какие-то закорючки. Первое, что приходит в голову — это какая-то проблема с кодировкой. Нужно разобраться, в какой момент она возникает.

Посмотрим, какая кодировка у файла с нашим кодом. Она отображается в правом нижнем углу окна. Видим, что это UTF-8.

А какая кодировка используется в OC? Определить это можно разными путями. Например, в реестре (для его запуска в консоли напишите команду regedit) в Windows по следующему адресу можно посмотреть, чему равен параметр под названием ACP (ANSI code page):

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage

Содержимое реестра по указанному адресу:

У меня он имеет значение 1251. Это стандартная кодировка для русских версий Windows. У вас она может быть другой — все зависит от языка (кодировки) системы.

Есть еще один способ узнать кодировку, который подходит для любой ОС — это воспользоваться Java, поместив в наш класс две новых строки:

import java.nio.charset.Charset; public class MyFirstApp { public static void main(String[] args) { System.out.println(Charset.defaultCharset().displayName()); } }

Вникать в то, что означает этот код мы не будем — наша задача лишь получить универсальным способом значение кодировки. Но если в двух словах, то в первой строке мы подключаем класс Charset, а в пятой выводим значение кодировки для ОС, воспользовавшись возможностями данного класса.

Запускаем и видим то же значение, что и в реестре.

> java MyFirstApp.java windows-1251

Осталось узнать кодировку консоли. Для этого в ней напишем команду chcp.

> chcp Текущая кодовая страница: 866

Она выдала 866. Это же число можно наблюдать и в реестре у параметра OEMCP (Original equipment manufacturer code page). Это DOS-кодировка, которая досталась нам по наследству.

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

Дело в том, что во время компиляции компилятор определяет кодировку исходного кода, опираясь на значение кодировки по умолчанию (на кодировку вашей ОС), а не на кодировку файла. В разных системах используются разные кодировки по умолчанию: в Windows — windows-1251, в Linux и macOS — UTF-8.

В Windows, ко всему прочему, еще и кодировка консоли не совпадает с кодировкой системы! Консоль по историческим причинам имеет кодировку Cp866 (видимо, в целях совместимости).

Затем JVM определяет кодировку по умолчанию во время запуска, используя системное свойство file.encoding. Значение для этого свойства устанавливается Java-машиной один раз при старте на основании данных, взятых из ОС.

Кодировка, используемая при выводе в консоль тоже системная, а не консоли. Если они не совпадают, то не видать нам корректного вывода кириллицы.

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

Давайте исправлять ситуацию.

У компилятора есть опция -encoding. Она позволяет принудительно указать кодировку исходника, чтобы он не определял ее, опираясь на кодировку системы. Как вы помните, файл имеет кодировку UTF-8. Соединив вместе все эти сведения, компиляцию и запуск следует выполнить так:

> javac -encoding utf8 MyFirstApp.java > java MyFirstApp Написано однажды, работает везде

При компиляции (скрытой) и запуске однофайловых программ необходимо использовать другой способ (описанный выше не сработает):

> java -Dfile.encoding=UTF8 MyFirstApp.java Написано однажды, работает везде

-Dfile.encoding — это уже параметр JVM, устанавливающий принудительно нужное значение кодировки в системное свойство file.encoding благодаря которому, как писалось выше, JVM определяет кодировку во время запуска.

От всех этих параметров и правил может закружиться голова. И все эти годы Java-разработчики жили и мучились с кодировками и ошибками, которые они вызывали в программах.

Но не прошло и 25 лет, как появилась хорошая новость. Начиная с Java 18, значение кодировки по умолчанию определяется не исходя из кодировки ОС, а исходя из того, что она является по умолчанию UTF-8. Никакие параметры больше не нужны. Убедимся в этом:

> java MyFirstApp.java Написано однажды, работает везде > javac MyFirstApp.java > java MyFirstApp Написано однажды, работает везде

6. Создание JAVA_TOOL_OPTIONS

Для тех, кто сидит на Java меньше 18, придется использовать все параметры, указанные ранее — ни куда от них не деться. Но и тут есть выход.

Для устранения неудобства, связанного с ручным указанием кодировки, необходимо создать системную переменную JAVA_TOOL_OPTIONS (ранее мы уже имели дело с другой переменной —JAVA_HOME) со значением:

-Dfile.encoding=UTF8

Не забудьте перезапустить консоль

Благодаря этой переменной кодировка будет устанавливаться автоматически при каждом запуске JVM. При этом в консоли будет отображаться сообщение (не обращайте на него внимание):

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8

Пробуем скомпилировать и запустить с установленным JAVA_TOOL_OPTIONS:

> java MyFirstApp.java Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Написано однажды, работает везде > javac MyFirstApp.java Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 > java MyFirstApp Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Написано однажды, работает везде

7. Ввод с клавиатуры

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

Подключим к нашему коду класс Scanner, который позволит считывать, введенные с клавиатуры символы:

import java.util.Scanner; public class MyFirstApp { public static void main(String[] args) { System.out.println("Написано однажды, работает везде"); Scanner console = new Scanner(System.in); System.out.print("Введите свое имя: "); System.out.println(console.nextLine()); } }

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

> java MyFirstApp.java Написано однажды, работает везде Введите свое имя: Максим ????

Это означает, что кодировка консоли и кодировка, которую использует Scanner, не совпадают.

Проблему можно решить, указав явно cp866 — это кодировка консоли:

замените Scanner console = new Scanner(System.in); на Scanner console = new Scanner(System.in, "cp866");

Снова запустим программу:

> java MyFirstApp.java Написано однажды, работает везде Введите свое имя: МАКСИМ ШШШШ ИИИИ МАКСИМ ШШШШ ИИИИ

Как видим, текст отображается корректно.

Если после всего проделанного, что я описал выше, у вас вместо русского текста выводится пустая строка, то необходимо в консоли ввести chcp 866 и заново запустить программу.

Заключение

В этой статье мы научились компилировать и запускать java-программы, нашли способ побороть проблему с выводом кириллических символов в консоль, а также лучше стали понимать, как работают все эти механизмы.

Ниже перечислены ключевые моменты статьи:

  • javac MyFirstApp.java — компиляции java-файла
  • java MyFirstApp — запуск Java-программы
  • javap -c MyFirstApp.class — вывод байт-кода
  • java MyFirstApp.java — компиляция (скрытая) и запуск однофайловых программ
  • javac -encoding utf8 MyFirstApp.java — компиляция программы с указанием кодировки исходника
  • java -Dfile.encoding=UTF8 MyFirstApp.java — компиляция (скрытая) и запуск однофайловых программ с явным указанием кодировки
  • JAVA_TOOL_OPTIONS — системная переменная для хранения кодировки для JVM
  • Scanner sc = new Scanner(System.in, "cp866") — решение проблемы с выводом русских символов через явное указание кодировки консоли

Автор: Чимаев Максим

Друзья, если вам понравилась статья, и вы изучаете Java, то приглашаем вас на курс для начинающих с нуля StartJava. Под руководством ментора Максима вы сможете с самых азов освоить язык Java. Курс очень насыщенный и постоянно развивается. Более сотни положительных отзывов.

Контакты:

0
Комментарии
-3 комментариев
Раскрывать всегда