код hello world java
Java байткод «Hello world»
На хабре уже есть статья про java байткод. Я решил ее немного дополнить и в меру сил развить тему. Мне кажется довольно логичным разобрать простейшее приложение на Java. А что может быть проще «Hello world»?
Для своего эксперимента я создал директорию src, куда в папку hello положил файл App.java:
Скопилируем файл командой:
На выходе в папке classes у меня появился файл App.class Для начала сравним размеры java и class файлов.
App.java 139B
App.class 418B
Это было неожиданно. Мне почему-то казалось, что скомпилированный файл должен быть меньше. Попытаюсь открыть class файл:
Довольно непривычный вид для Java кода. Попробуем с помощью описание формата class файлов понять, что здесь закодировано.
Это 4 байта для magic, который определяет формат файла.
minor version — Минорная версия как следует из названия
major version — 2 байта под мажорную версию.
Сочетание minor и major version говорит о том, что я компилировал этот код с помощью J2SE 8.
Эти два байта представляют constant_pool_count и отвечают за размер constant_pool. В моем случае count равен 29, а размер пула, соответственно 28. Дальше идут элементы вида:
cp_info <
u1 tag; // 1 байт на тег
u1 info[]; // массив с описанием
>
Рассмотрим элементы в constant_pool.
Этот тег соответствует CONSTANT_Methodref, а значит дальше должно быть описание:
CONSTANT_Methodref_info <
u1 tag;
u2 class_index;
u2 name_and_type_index;
>
соответственно:
class_index, указывает на 6 элемент в constant_pool
name_and_type_index, указывает на 15 элемент в constant_pool
Пока не понятно, на какой метод указывает эта ссылка и мы идем дальше:
Это CONSTANT_Fieldref, а значит дальше ищем:
CONSTANT_Fieldref_info <
u1 tag;
u2 class_index;
u2 name_and_type_index;
>
И тут все очень похоже на предыдущий элемент, хотя не понятно что это за поле, в своем классе я вроде ничего такого не объявлял.
class_index в 16 элементе
name_and_type_index в 17 элементе
tag для CONSTANT_String
получаем, что самое интересное лежит в 18 элементе:
Tag соответствующий ссылке на метод:
класс которого описан в 19 элементе
a название и тип в 20 элементе:
5-ый элемент:
Tag для CONSTANT_Class
название, которого в 21 элементе
6-ой элемент:
Cнова CONSTANT_Class
c названием в 22 элементе
Как мы помним 1-ый элемент constant_pool относится к этому классу.
7-ой элемент:
tag, CONSTANT_Utf8, первая строчка
Она должна соответствовать:
CONSTANT_Utf8_info <
u1 tag;
u2 length;
u1 bytes[length];
>
Тогда длина нашей строчки 6 байт:
Это особое название, так помечаются конструкторы.
строчка длины 3 — «()V»:
Это описание нашего конструктора без параметров, который был упомянут в седьмом элементе.
9-ый элемент:
CONSTANT_Utf8
10-ый элемент:
Строка LineNumberTable
15-ый элемент
Tag, соответствует CONSTANT_NameAndType
а значит нам понадобится
CONSTANT_NameAndType_info <
u1 tag;
u2 name_index;
u2 descriptor_index;
>
и тогда:
ссылка на 7 элемент
ccылка на 8 элемент
Учитывая что первый элемент ссылался на это, мы можем заключить что первым был объявлен конструктор класса без параметров. Название класса, мы должны найти в 22 элементе.
16-ый элемент:
Tag, для CONSTANT_Class
c названием в 23 элементе
17-ый элемент:
Tag, CONSTANT_NameAndType, со ссылкой на 24 и 25 элемент constant_pool
18-ый элемент:
Ура «Hello world!»
19-ый элемент:
Tag, для CONSTANT_class c названием в 25-ом элементе
20-ый элемент:
Tag CONSTANT_NameAndType cо ссылкой на 27 и 28 элемент
25-ый элемент:
«Ljava/io/PrintStream;»
26-ой элемент:
«java/io/PrintStream»
methods_count у нас 2 метода в классе, конструктор по умолчанию и метод main:
Method 1 — Constructor
Один из самых интересных аттрибутов с кодом нашего метода code[code_length], разбор инструкций отдельная большая тема:
Аттрибут закончился и продолжается описание метода
Attribute 1 код метода main
Описание методов закончено и идет описание атрибутов класса
Теперь когда мы закончили с по-байтовым разбором class файла, становится понятно как работает:
Он автоматически выводит тоже самое, что я выписал руками:
А вот здесь можно посмотреть пример разбора class файла:
Hello World из байт-кода для JVM
Скомпилируем простенькую программу выводящую «Hello World» и пройдемся по его структуре
Не думаю, что статья будет достаточно информативной для тех, кто поверхностно не знает как выглядит байт-код и как с ним работает JVM (например, хотя бы простейшие инструкции (знание об их существовании)).
На самом деле, это не так сложно. Достаточно использовать инструмент javap из JDK и рассмотреть дизассемблированный код.
А мы приступим к разбору самой структуры байт-кода для JVM
Очень полезной книгой для этого стала официальная спецификация JVM — The Java Virtual Machine Specification на сайте oracle
Для начала создадим простенькую программу:
Скомпилируем её командой javac Main.java и собственно сделаем дизассемблинг
Это просто представление байт-кода, которое человеку видеть легче, чем оригинальный байт-код, но сам он выглядит иначе:
С этим кодом мы и будем работать.
Но для начала нам нужно его отформатировать, чтобы не путаться что где находится, а байт-код, на самом деле, имеет вполне жесткую структуру:
Её вы можете найти в спецификации JVM Chapter 4.1 The ClassFile Structure
Тут все просто — слева указана размерность в байтах, а справа описание.
Разбирать байт-код мы будем в hexadecimal, где каждая цифра занимает 4 бита, а следовательно, на два байта — 4 цифры и на четыре байта — 8 цифр.
magic
minor_version, major_version
Это версии вашего class файла. Если мы назовем major_version M и minor_version m, то получаем версию нашего class файла как M.m
Сейчас я сразу буду приводить примеры из нашей программы «Hello World», чтобы посмотреть как они используются:
Его же мы можем видеть в дизассемблированном коде, но уже в десятичной системе счисления:
constant_pool_count
Здесь указывается количество переменных в пуле констант. При этом, если вы решили писать код на чистом байт-коде, то вам обязательно нужно следить за его значением, так как если вы укажете не то значение, то вся программа полетит к чертям (проверено!).
Также следует не забывать, что вы должны писать туда количество_переменных_в_пуле + 1
constant_pool[]
Каждый тип переменной в пуле констант имеет свою структуру:
Таблица с тэгами можно найти в спецификации Table 4.3 Constant pool tags
Собственно, вот табличка:
Constant Type | Value |
---|---|
CONSTANT_Class | 7 |
CONSTANT_Fieldref | 9 |
CONSTANT_Methodref | 10 |
CONSTANT_InterfaceMethodref | 11 |
CONSTANT_String | 8 |
CONSTANT_Integer | 3 |
CONSTANT_Float | 4 |
CONSTANT_Long | 5 |
CONSTANT_Double | 6 |
CONSTANT_NameAndType | 12 |
CONSTANT_Utf8 | 1 |
CONSTANT_MethodHandle | 15 |
CONSTANT_MethodType | 16 |
CONSTANT_InvokeDynamic | 18 |
Как ранее уже говорилось, каждый тип константы имеет свою структуру.
Вот, например, структура CONSTANT_Class :
Структура поля и метода:
Тут важно заметить, что разные структуры, могут иметь разную длину.
Рассмотрим часть нашего кода:
Итак, смотрим на структуру константы и узнаем, что первый байт отведен под тип константы. Здесь мы видим 0a (10) — а, следовательно, это CONSTANT_Methodref
Смотрим его структуру:
После одного байта для тэга, нам нужно еще 4 байта для class_index и name_and_type_index
Отлично, мы нашли одну из значений пула констант. Идем дальше. Смотрим, 09 — значит тип CONSTANT_Fieldref
Вам может показаться, что большинство типов имеет одинаковую форму, но это не так.
Например, структура следующего типа выглядит так, CONSTANT_String :
Все эти структуры можно посмотреть в Chapter 4.4 The Constant Pool
Теперь разберем, что значат типы внутри самого info
Это же мы можем видеть в дизассемблированном коде:
Также можно выделить представление чисел и строк.
Про представление чисел можно прочитать начиная с главы 4.4.4, а мы пока разберем лишь строки, так как числа пока не входят в программу Hello World
Собственно, вот так представляется строка:
Например, наш Hello World:
Разбирая весь пул констант байт-кода, получим:
Также, мы можем сравнить его с дизассемблированным кодом:
Тем самым проверив, что все совпадает, ведь по сути javap просто обрабатывает этот байт-код и показывает нам его в форматированном виде.
Пул констант нужен для инструкций. Например:
Подробнее обо всех типах в пуле констант можно узнать в Chapter 4.4 The Constant Pool
Идем дальше по структуре ClassFile
access_flags
Это битовая маска для свойств модификаторов
Flag Name | Value | Interpretation |
---|---|---|
ACC_PUBLIC | 0x0001 | Declared public ; may be accessed from outside its package. |
ACC_FINAL | 0x0010 | Declared final ; no subclasses allowed. |
ACC_SUPER | 0x0020 | Treat superclass methods specially when invoked by the invokespecial instruction. |
ACC_INTERFACE | 0x0200 | Is an interface, not a class. |
ACC_ABSTRACT | 0x0400 | Declared abstract ; must not be instantiated. |
ACC_SYNTHETIC | 0x1000 | Declared synthetic; not present in the source code. |
ACC_ANNOTATION | 0x2000 | Declared as an annotation type. |
ACC_ENUM | 0x4000 | Declared as an enum type. |
this_class
Должна содержать адрес на this класса. В нашем случае, она находится по адресу 5:
Следует заметить, что структуру этой переменной должна соответствовать CONSTANT_Class_info
super_class
То есть в этих ячейках указан name_index из структуры:
interfaces_count, fields_count
methods_count
Количество методов. Хоть и в коде мы видим один метод в классе, но, на самом деле, их два. Кроме main метода еще есть конструктор по умолчанию. Поэтому их количество равно двум, в нашем случае.
methods[]
Каждый элемент должен соответствовать структуре method_info описанной в Chapter 4.6 Methods
В нашем байт-коде (отформатированном, с комментариями) выглядит это так:
Разберем по-подробнее структуру методов:
access_flags
К слову, ACC_VARARGS здесь необязательный, в том плане, что, если бы мы
использовали String[] args вместо String… args, то этого флага бы не было
name_index
descriptor_index
Грубо говоря, это адрес указывающий на дескриптор метода. Этот дескриптор содержит тип возвращаемого значения и тип его сигнатуры.
Также, в JVM используются интерпретируемые сокращения:
BaseType Character | Type | Interpretation |
---|---|---|
B | byte | signed byte |
C | char | Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 |
D | double | double-precision floating-point value |
F | float | single-precision floating-point value |
I | int | integer |
J | long | long integer |
L ClassName ; | reference | an instance of class ClassName |
S | short | signed short |
Z | boolean | true or false |
[ | reference | one array dimension |
В общем случае это выглядит так:
Например, следующий метод:
Можно представить в виде
Далее, идут атрибуты, которые также имеют свою структуру.
Но сначала, как и всегда, идет его количество attributes_count
Затем сами атрибуты со структурой описанной в Chapter 4.7 Attributes
attribute_name_index
attribute_length
Содержит длину атрибута, не включая attribute_name_index и attribute_length
info
max_stack
Мне кажется, что имя этого атрибута может ввести в заблуждение из-за приставки max. На самом деле, это минимальный размер стека нужный для выполнения операции. Ну, это имя приобретает логику, если сказать, максимальный размер стека, который будет достигнут во время выполнения операции.
Упрощенно говоря, JVM выделит место для стека операндов. Там можно указывать значение, которое больше, чем нужно, но определение в этом атрибуте значения меньше, чем нужно приведет к ошибке.
max_locals
Максимальный размер локальных переменных
Ознакомится с локальными переменными можно либо в Mastering Java Bytecode at the Core of the JVM или в том же JVM Internals
code_length
Размер кода, который будет исполнятся внутри метода
code[]
Каждый код указывает на какую-то инструкцию. Таблицу соотношения optcode и команды с мнемоникой можно найти в википедии — Java bytecode instruction listings или в самой спецификации в конце книги
Для примера, возьмем наш конструктор:
Здесь мы можем найти наш код:
Ищем в таблице команды и сопоставляем:
Также описания этих команд можно найти здесь: Chapter 4.10.1.9. Type Checking Instructions
exception_table_length
Задает число элементов в таблице exception_table. У нас пока нет перехватов исключений поэтому разбирать его не будем. Но дополнительно можно почитать Chapter 4.7.3 The Code Attribute
exception_table[]
Имеет вот такую структуру:
attributes_count
Количество атрибутов в Code
attributes[]
Атрибуты, часто используются анализаторами или отладчиками.
Средства для работы с байт-кодом
Это немного не та тема, которая относится к данной статье, но все же косвенно связанная с ней.
Средств для работы с байт-кодом, на самом деле, достаточно много. Здесь я бы хотел рассмотреть Byte Code Engineering Library (BCEL) от Apache Commons.
Для начала, с помощью него мы может получить некоторые атрибуты байт-кода:
Помимо этого мы можем сгенерировать, изменить или дизассемблировать (например, в Jasmin) байт-код.
Парочку примеров можно найти в моем репозитории или в официальных примерах
Также, я уделил внимание и Jasmin. На самом деле, я не знаю, чем оно может быть полезно, но я её использовал при изучении механизма работы JVM с байт-кодом.
С помощью неё можно писать на упрощенном ассемблерном коде:
Вот мы и разобрали простую программку Hello World
Листинг байт-кода с комментариями можно найти на моем гисте: gist.github
Если есть ошибки прошу писать в комментариях или в сообщениях.
Java Core для самых маленьких. Часть 1. Подготовка и первая программа
Вступление. Краткая история и особенности языка
Как-то давно мы с моим товарищем и коллегой Егором готовили обучающий курс по Java Core. Но как-то не срослось и это дело не было доведено до какого-либо логического конца. И вот, спустя время, я решил, что не стоит пропадать добру и по-этому запускаю серию статей про Java Core для самых маленьких.
Начало разработки языка было положено еще в 1991 году компанией Sun Microsystems, Inc. Вначале язык был назван Oak (Дуб), но в 1995 он был переименован в Java. Публично заявили о создании языка в 1995 году. Причиной создания была потребность в независящем от платформы и архитектуры процессора языке, который можно было бы использовать для написания программ для бытовой электротехники. Но поскольку в таких устройствах применялись различные процессоры, то использование популярных на то время языков С/С++ и прочих было затруднено, поскольку написанные на них программы должны компилироваться отдельно для конкретной платформы.
Для того чтобы скачать и установить JDK открываем браузер, и в строке поиска Google вводим “download JDK” или переходим по этой ссылке.
Скролим ниже и находим таблицу с вариантами скачивания JDK. В зависимости от нашей операционной системы выбираем файл для скачивания.
Процесс установки для ОС Windows имеет несколько этапов. Не стоит пугаться, все очень просто и делается в несколько кликов. Вот здесь подробно описан процесс установки. Самое важное для пользователей Windows это добавить системную переменную JAVA_HOME. В этой же статье достаточно подробно расписано как это сделать (есть даже картинки).
Установка IDE
Теперь нам нужно установить среду разработки, она же IDE (Integrated development environment). Что собой представляет среда разработки? На самом деле она выглядит как текстовый редактор, в котором мы можем вводить и редактировать текст. Но помимо этого, этот текстовый редактор умеет делать проверку синтаксиса языка на котором вы пишете. Делается это для того чтобы на раннем этапе подсказать вам о том, что вы допустили ошибку в своем коде.
Кроме этого, среда разработки поддерживает отладчики которые помогают править и отлаживать ваш код в случае ошибки. Скажем так, это были описаны основные возможности IDE. Современные IDE предоставляют огромное количество инструментов, которые могут помочь в написании, отладке, автоматической генерации кода и решить множество других проблем.
Для начала нам нужно выбрать и среду разработки. Их довольно таки много, и самыми популярными из них являются: IntelliJ IDEA, NetBeans, Eclipse. Для себя я выбираю IntelliJ IDEA. Она является самой удобной на мой взгляд, и хоть она и платная, на официальном сайте можно найти бесплатную версию которая называется Community. Этой версии будет вполне достаточно для изучения основ Java. Вообщем будем работать в IntelliJ IDEA.
Итак, открываем браузер, в поисковой строке вводим «Download IntelliJ IDEA Community» или переходим по этой ссылке. Выбираем версию ОС и качаем версию Community.
В установке IntelliJ IDEA нет ничего военного. На крайний случай на ютубе есть множество видео о том, как установить эту программу.
Первая программа
Теперь мы готовы создать нашу первую программу. В окошке запустившийся IDE нажимаем New Project.
В новом окошке в левой панели выбираем Java.
Обратите внимание! В верхнем окошке, справа, возле надписи «Project SDK:» должна находится версия Java, которую вы установили вместе с JDK. Если там пусто, то вам нужно будет указать путь к вашему JDK вручную. Для этого в выпадающем списке нажмите «Add JDK. « и укажите путь к вашему JDK, который был предварительно установлен.
Теперь можем нажать на кнопку Next. В следующем окошке, вверху, поставьте галочку “Create project from template” и выберите “Command Line App”. И снова нажимаем Next.
Дальше нам нужно указать имя программы. У меня это будет Hello World, желательно чтобы имя проекта было введено латиницей, и на английском языке.
Примечание. Все программы, имена программ, принято писать на английском языке, и желательно придерживаться такого стиля, что является хорошим тоном в программировании.
После указываем путь к проекту программы.
После этого вы увидите главное окно IDE, в котором уже будет создана ваша первая, почти готовая консольная программа.
Это окно, то что вы будете видеть 80-90%, а иногда и 100% времени, работая программистом.
Для того чтобы закончить ваше первое приложение, останется добавить строчку кода System.out.print(«Hello world!»); как показано на скриншоте.
Разбираем первую программу
В своем первом приложении вы можете увидеть много непонятных символов и слов, но на данном этапе вы должны воспринять их как данность, позже, в следующих частях, я расскажу о каждом из них, и зачем они нужны. На данном этапе вам нужно понять что это стандартные составляющие любого Java-приложения, и в последующих приложениях эти компоненты будут изменяться минимально.
Пройдемся по порядку:
Фигурные скобки <> у метода main обозначаю начало и конец тела метода, весь код метода должен располагаться между этими скобками. Аналогичные скобки есть и у класса Main.
Следующая строка является // write your code here однострочным комментарием.
Комментарием является текст который игнорируется компилятором. По-этому с помощью комментариев вы можете оставлять в коде подсказки для себя и других, кто будет читать ваш код, или же для документирования вашего кода. Существует несколько видов комментариев, основными из них являются однострочный, и многострочный.
Многострочный комментарий будет выглядеть следующим образом:
Мы просто располагаем несколько строк между символами /* и */
Обратите внимание что в конце стоит точка с запятой, в языке Java команды должны заканчиваться точкой с запятой.
На этом статья подходит к концу. Автором конкретно этого материала является Егор и все уменьшительно ласкательные формы слов сохранились в первозданном виде.
В следующей статье мы поговорим о типах данных в Java.
Код hello world java
В этом уроке мы создадим нашу первую программу на языке Java.
Создание приложения на языке Java состоит из трех следующих шагов:
Создание исходного файла
Итак, открываем текстовый редактор и пишем в нем код программы Hello World, цель которой — вывод на экран сообщения Hello World!
Если вы пользуетесь Notepad++ то нужно выбрать Тип файла:Java source file (*.java)
Будьте внимательны! файл должен называться в точности так, как называется наш класс — HelloWorld. Так же важно учитывать регистр букв. HelloWorld и helloworld в данном случае это разные слова!
Компиляция исходного файла
Исходный файл с кодом программы создан, теперь перейдем к компиляции. Для компиляции Java предназначен компилятор javac, который входит в состав установленного нами в первом уроке пакета JDK.
Для того, чтобы скомпилировать исходный файл, открываем командную строку. Для этого в меню Windows Пуск в строке поиска вводим команду cmd и жмем Enter. После этого откроется командное окно.
Теперь в нем нужно изменить текущий каталог на тот, в котором находится наш исходный файл (например C:\studyjava\). Для этого вводим следующую команду:
После того, как директория изменилась, вводим команду компиляции
После этого, окно командной строки должно выглядеть следующим образом (рис 2.2):
То есть, мы не получим никакого подтверждения, о том, что программа скомпилировалась успешно. Однако, в папке с нашим исходным файлом, должен появиться файл HelloWorld.class. Это можно проверить с помощью команды
Эта команда выводит на экран список всех файлов, находящихся в выбранной директории (рис 2.3).
Если файл HelloWorld.class присутствует в этом списке, то это значит, что программа скомпилировалась успешно.
Если в коде программы есть ошибка, то компилятор Java при компиляции нам об этом сообщит.
Проведем эксперимент: Откроем в текстовом редакторе наш файл HelloWorld.java и удалим последнюю закрывающуюся фигурную скобку «>». Сохраним файл и попробуем его еще раз скомпилировать. В итоге получаем сообщение об ошибке (рис 2.4).
Чтобы исправить ошибку, нужно вновь открыть файл для редактирования, устранить ошибку, сохранить файл и еще раз его скомпилировать.
Запуск программы
Переходим к последней стадии — запуску программы.
Вводим в командном окне:
и если все перед этим было сделано правильно, то получаем результат — вывод сообщения «Hello World!» (рис 2.5).
Еще раз обратите внимание на чувствительность к регистру в Java. Если вы напишете helloworld вместо HelloWorld, то программа запущена не будет, потому что Java попросту не найдет файл с таким именем.
В качестве домашнего задания можете поэкспериментировать и выводить на экран какое-либо свое сообщение вместо Hello World!.