Содержание
Как работает виртуальная машина Java — взгляд изнутри
Рассказывает Роман Иванов
Каждому Java-разработчику будет очень полезно понимать, что из себя представляет JVM, как в неё попадает код и как он исполняется. Статья больше подойдёт новичкам, но найти в ней что-то новое смогут и более опытные программисты. В статье вкратце описано, как устроен class-файл и как виртуальная машина обрабатывает и исполняет байт-код.
Основной задачей разработчиков Java было создание переносимых приложений. JVM играет центральную роль в переносимости — она обеспечивает должный уровень абстракции между скомпилированной программой и базовой аппаратной платформой и операционной системой. Несмотря на этот дополнительный «слой», скорость работы приложений необычайно высока, потому что байт-код, который выполняет JVM, и она сама отлично оптимизированы.
Рассмотрим схему работы JVM более подробно.
Структура class-файла
Напишем простейшее приложение и скомпилируем его. Компилятор заботливо создаст файл с расширением class и поместит туда всю информацию о нашем мини-приложении для JVM. Что мы увидим внутри? Файл поделён на десять секций, последовательность которых строго задана и определяет всю структуру class-файла.
Файл начинается со стартового (магического) числа: 0xCAFEBABE. Данное число присутствует в каждом классе и является обязательным флагом для JVM: с его помощью система понимает, что перед ней class-файл.
Следующие четыре байта class-файла содержат старший и младший номера версий Java. Они идентифицируют версию формата конкретного class-файла и позволяют JVM проверять, возможна ли его поддержка и загрузка. Каждая JVM имеет ограничение версии, которую она может загрузить — более поздние версии будут игнорироваться. Как видно на примере файла выше, у нас major версия 0x34
, что соответствует Java SE 8. Для Java SE 11 будет значение 0x37
.
С девятого байта идёт пул констант, в котором содержатся все константы нашего класса. Так как в каждом классе их может быть различное количество, то перед массивом находится переменная, указывающая на его длину, то есть пул констант представляет из себя массив переменной длины. Каждая константа занимает один элемент в массиве. Во всём class-файле константы указываются целочисленным индексом, который обозначает их положение в массиве. Начальная константа имеет индекс 1, вторая константа — 2 и т. д.
Каждый элемент пула констант начинается с однобайтового тега, определяющего его тип. Это позволяет JVM понять, как правильно обработать идущую далее константу. Всего зарезервировано 14 типов констант:
Тип константы | Значение тега |
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 |
Например, если тег указывает, что константа является строкой, JVM получает значение тега 1 и обрабатывает следующее за тегом число как длину массива байт, которые необходимо считать, чтобы получить нужную нам строку полностью.
Прочитав блок с константами, JVM переходит к следующим двум байтам — флагам доступа, которые определяют, описывает этот файл класс или интерфейс, общедоступный или абстрактный, является ли класс финальным.
Имена класса и его родительского класса хранятся в массиве констант, на которые указывают последующие 4 байта в файле.
Немного иначе обстоят дела с интерфейсами. Так как класс может наследоваться от множества интерфейсов одновременно, то хранить необходимо массив ссылок на пул констант. То есть за определением класса и его родительского класса идёт число, характеризующее размер массива интерфейсов, и сам массив. Все возможные значения кодов представлены ниже.
Имя флага | Код | Определение |
ACC_PUBLIC | 0x0001 | Объявлен публичным |
ACC_FINAL | 0x0010 | Объявлен финальным |
ACC_SUPER | 0x0020 | Специальный флаг, введённый в версии Java 1.![]() |
ACC_INTERFACE | 0x0200 | Объявлен интерфейсом |
ACC_ABSTRACT | 0x0400 | Объявлен абстрактным |
ACC_SYNTHETIC | 0x1000 | Зарезервированное определение |
ACC_ANNOTATION | 0x2000 | Объявлен аннотацией |
ACC_ENUM | 0x4000 | Объявлен перечислением |
Подобную структуру имеет и следующий блок — Fields.
Этот блок начинается с двухбайтового параметра количества полей в этом классе или интерфейсе. За ним идёт массив структур переменной длины. Каждая структура содержит информацию об одном поле: имя поля, тип, значение, если это, например, финальная переменная. В списке отображаются только те поля, которые были объявлены классом или интерфейсом, определённым в файле. Поля от родительских классов и имплементированных интерфейсов здесь не присутствуют, они задаются в своих class-файлах.
Далее мы переходим к самому важному месту в любом классе — его методам, именно в них сосредоточена вся логика любой программы, весь исполняемый байт-код.
Ситуация абсолютно аналогична описанным выше полям. В массиве переменной длины содержатся структуры, в которые входит полное описание сигнатуры метода: модификаторы доступа, имя метода и его атрибуты, которые также представляют из себя структуру, так как их может быть множество и каждый из них может принадлежать разным типам.
В последнем блоке идёт дополнительная мета-информация, например имя файла, который был скомпилирован. Она может присутствовать, а может и нет. В случае каких-то проблем JVM просто игнорирует этот блок.
Мы рассмотрели структуру файлов и готовы перейти к следующей части — загрузке class-файла в JVM и последующему выполнению байт-кода из этого класса. В качестве закрепления полученных знаний по структуре class-файла можете воспользоваться встроенным декомпилятором Java и посмотреть результат его выполнения с ключами -c -verbose (javap -c -verbose TestJava.
. class)
Загрузка классов
Теперь, разобравшись с общей структурой файла, посмотрим, как JVM его обрабатывает.
Чтобы попасть в JVM, класс должен быть загружен. Для этого существуют специальные классы-загрузчики:
- Bootstrap — базовый загрузчик, загружает платформенные классы. Этот загрузчик является родителем всех остальных классов и частью платформы.
- Extension ClassLoader — загрузчик расширений, потомок Bootstrap-загрузчика. Загружает классы расширений, которые по умолчанию находятся в каталоге
jre/lib/ext
. - AppClassLoader — системный загрузчик классов из classpath, который является непосредственным потомком Extension ClassLoader. Он загружает классы из каталогов и jar-файлов, указанных переменной среды
CLASSPATH
, системным свойствомjava.class.path
или параметром командной строки-classpath
. - Собственный загрузчик — у приложения могут быть свои собственные загрузчики.
Главный класс приложения всегда загружается системным загрузчиком, остальные же классы могут быть загружены различными пользовательскими загрузчиками. Стоит упомянуть, что имя загрузчика создаёт уникальное пространство имён, то есть в программе может существовать несколько классов с одним и тем же полным именем, если они обрабатывались разными загрузчиками.
Поэтому каждый загрузчик делегирует свои полномочия родителю, то есть перед поиском класса для загрузки он попытается узнать, не был ли загружен нужный класс раньше.
После загрузки класса начинается этап линковки, который делится на три части.
- Верификация байт-кода. Это статический анализ кода, выполняется один раз для класса. Система проверяет, нет ли ошибок в байт-коде. Например, проверяет корректность инструкций, переполнение стека и совместимость типов переменных.
- Выделение памяти под статические поля и их инициализация.
- Разрешение символьных ссылок — JVM подставляет ссылки на другие классы, методы и поля.
В большинстве случаев это происходит лениво, то есть при первом обращении к классу.
Класс инициализируется, и JVM может начать выполнение байт-кода методов.
JVM получает один поток байтовых кодов для каждого метода в классе. Байт-код метода выполняется, когда этот метод вызывается в ходе работы программы. Поток байт-кода метода — это последовательность инструкций для виртуальной машины Java. Каждая инструкция состоит из однобайтового кода операции, за которым может следовать несколько операндов. Код операции указывает действие, которое нужно предпринять. Всего на данный момент в Java более 200 операций. Все коды операций занимают только 1 байт, так как они были разработаны компактными, поэтому их максимальное число не может превысить 256 штук.
В основе работы JVM находится стек — основные инструкции работают с ним.
Рассмотрим пример умножения двух чисел. Ниже представлен байт-код метода:
0: iconst_1 // взять число 1, положить в стек 1: istore_1 // сохранить это число в переменную 1 стека метода 2: iconst_5 // взять число 5, положить в стек 3: istore_2 // сохранить его в переменную 2 стека метода 4: iload_1 // положить в стек переменную 1 5: iload_2 // положить в стек переменную 2 6: imul // достать из стека два числа, умножить их и положить в стек 7: istore_3 // взять из стека число и сохранить его в переменную 3
На Java это будет выглядеть так:
int a = 1; int b = 5; int c = a * b
По листингу выше можно заметить, что коды операций сами по себе указывают тип и значение. Например, код операции
iconst_1
указывает JVM на целочисленное значение, равное единице. Такие байт-коды определены для самых часто используемых констант. Эти инструкции занимают 1 байт и введены специально для повышения эффективности выполнения байт-кода и уменьшения размера его потока. Подобные короткие константы также присутствуют и для других типов данных.
Всего JVM поддерживает семь примитивных типов данных: byte, short, int, long, float, double и char.
Если бы мы хотели положить в переменную а другое значение, например 11112, то нам пришлось бы использовать инструкцию sipush
:
0: sipush 11112 3: istore_1
Данные операции выполняются в так называемом фрейме стека метода. У каждого метода есть некоторая своя часть в общем стеке. Таким образом в нашем главном потоке исполнения программы создаются множество подстеков на каждый вызов метода. Более наглядно это представлено на картинке ниже:
В каждом стек-фрейме хранится массив локальных переменных, который позволяет сохранять и доставать локальные переменные, как мы сделали в примере выше, поместив значения 1 и 5 в переменные 1 и 2. Стоить отметить, что здесь компилятор также оптимизировал байт-код, используя однобайтовые инструкции. Если бы переменных в нашем методе было много, использовался бы код операции сохранения значения вместе с указанием позиции переменной в массиве.
Чтобы достучаться до пула констант класса и получить нужное значение, используются инструкции lcd
и lcd_w
. При этом lcd
может ссылаться только на константы с индексами от 1 до 255, поскольку размер её операнда составляет всего 1 байт. Lcd_w
имеет 2-байтовый индекс, поэтому может ссылаться на более широкий диапазон индексов.
Вызовы методов
Java предоставляет два основных вида методов: методы экземпляра и методы класса. Методы экземпляра используют динамическое (позднее) связывание, тогда как методы класса используют статическое (раннее) связывание.
Виртуальная машина Java вызывает метод класса, выбирая его на основании типа ссылки на объект, который всегда известен во время компиляции. С другой стороны, когда виртуальная машина вызывает метод экземпляра, она выбирает метод для вызова на основе фактического класса объекта, который может быть известен только во время выполнения. Поэтому для вызова методов используются разные инструкции:
invokevirtual
и invokestatic
. Данные функции ссылаются на запись в пуле констант в виде полного пути к необходимой функции. Виртуальная машина снимает нужное количество переменных со стека и передает в метод.
Возвращаемое методом значение кладётся на стек. Типы возвращаемых значений методов указаны ниже:
Операция | Описание |
ireturn | Помещает на стек значение типа int |
lreturn | Помещает на стек значение long, |
freturn | Помещает на стек значение float |
dreturn | Помещает на стек значение double |
areturn | Помещает на стек значение object |
return | Не изменяет стек |
Циклы
Осталось рассмотреть последнюю часто используемую конструкцию языка — циклы. Посмотрим, во что превратится код, представленный ниже:
int i = 1000; while (i < 9999) { i += 10; }
Байт-код:
0: sipush 1000 3: istore_1 4: iload_1 5: sipush 9999 8: if_icmpge 17 11: iinc 1, 10 14: goto 4 17: return
Каждый раз на стеке оказывается два числа, которые сравниваются, и если i > 9999
, происходит выход из цикла. При этом для создания цикла используется конструкция на основе goto
, которая запрещена в самом языке Java, хотя ключевое слово и зарезервировано.
Заключение
Изначально байт-код интерпретируется в большинстве JVM, но как только система замечает, что некоторый код используется очень часто, она подключает встроенный компилятор, который компилирует байт-коды в машинный код, тем самым значительно ускоряя работу приложения.
Таким образом, мы поверхностно рассмотрели жизненный цикл байткода в JVM: class-файлы, их загрузку и выполнение байт-кода и базовые инструкции.
Что такое JVM? Знакомство с виртуальной машиной Java
Java virtual machine (JVM) — это программа, которая разработана для выполнения и запуска других программ на основе Java. В основе JVM лежит простая и гениальная идея, которая всегда останется одним из величайших примеров программирования в стиле кунг-фу. JVM может также использоваться для выполнения программ, написанных на других языках программирования. Подробно рассказываем, как работает JVM, для чего используется эта технология и почему она является одним из главных компонентов в платформе Java. Материал основан на статье Java-разработчика Matthew Tyson «What is the JVM? Introducing the Java Virtual Machine».
- Для чего используется Java virtual machine
- Кто разрабатывает и обслуживает JVM?
- Сборка мусора
- Три главные части JVM
- Спецификация JVM
- Реализация JVM
- Экземпляр JVM
- Загрузка и выполнение class-файлов в JVM
- Загрузчик классов в JVM
- Механизм выполнения в JVM
- Управление системными ресурсами
- Эволюция JVM: прошлое, настоящее, будущее
Для чего используется Java virtual machine
JVM имеет две основные функции:
- Позволяет запускать программы, написанные на Java, на любых устройствах или операционных системах.
Так реализуется принцип Java — «Написал один раз, запускай везде».
- Управляет и оптимизирует память, которую используют программы.
Во время выхода первой версии Java в 1995 году все программы писались для конкретной операционной системы, а памятью управлял разработчик программного обеспечения. Поэтому появление JVM стало революцией на рынке.
Существует два основных определения JVM — техническое и повседневное:
- Техническое определение: JVM — это софт, который выполняет код и предоставляет среду для его выполнения.
- Повседневное определение: JVM — это способ запуска наших Java-приложений. Мы настраиваем параметры JVM, а потом полагаемся на ее автоматическое управление ресурсами во время выполнения.
Когда разработчики говорят о JVM, обычно имеется в виду процесс, который выполняется на нашем устройстве, особенно на сервере — он управляет и контролирует использование ресурсов Java-приложения.
Читайте также:
Язык программирования Java: особенности, популярность, ситуация на рынке труда
Кто разрабатывает и обслуживает JVM?
На сегодняшний день JVM массово используется и развивается в разных проектах — как коммерческих, так и Open Sourse. Например, существует проект OpenJDK, который представляет собой полностью совместимый Java Development Kit, состоящий исключительно из свободного и открытого исходного кода. При этом, несмотря на открытость кода этого проекта, его разработкой практически полностью занимается корпорация Oracle.
Сборка мусора
В Java памятью управляет JVM с помощью процесса, который называется сборкой мусора — он непрерывно определяет и удаляет неиспользуемую память в Java-приложениях. Сборка мусора происходит внутри работающей JVM.
В начале существования Java подвергалась серьезной критике за то, что не была «Close to the metal» как C++, поэтому не была такой быстрой. Особенно спорным критики называли процесс сборки мусора. С тех пор были предложены и использованы различные алгоритмы и подходы, которые значительно улучшили и оптимизировали сборку мусора.
Три главные части JVM
JVM состоит из трех основных частей: спецификация, реализация и экземпляр. Рассмотрим каждую из них.
Спецификация JVM
Первая часть JVM — спецификация, которая до конца не определяет все детали реализации виртуальной машины. Это значит, что остается максимальная свобода творчества для разработчика, который работает с ней. Чтобы правильно реализовать виртуальную машину Java, вам нужно всего лишь уметь читать class-файлы и правильно выполнять указанные в них операции.
И так, все, что должна делать JVM — правильно запускать Java-программы. Это может показаться достаточно простым процессом, однако это очень масштабная задача, учитывая мощность и гибкость языка Java.
Реализация JVM
Реализация спецификации JVM приводит к созданию реальной программы, которая и является реализацией JVM. По сути, существует огромное количество реализаций спецификации JVM — как коммерческих, так и с открытым кодом.
Экземпляр JVM
После того, как спецификация JVM реализована и выпущена в качестве самостоятельной программы, вы можете загрузить ее как приложение. Эта загруженная программа является экземпляром виртуальной машины.
Чаще всего, когда разработчики говорят о JVM, они имеют ввиду экземпляр JVM, который работает в среде разработки. Вы можете сказать: «Привет, сколько памяти использует JVM на этом сервере?» или «Я не могу поверить, что сделал зацикленный вызов, а переполнение стека сломало мою JVM. А ведь это просто ошибка новичка!»
Загрузка и выполнение class-файлов в JVM
Мы говорили о роли JVM в запуске Java-приложений, но как виртуальная машина выполняет свою функцию? Для запуска Java-приложений JVM зависит от загрузчика классов и механизма выполнения Java.
Загрузчик классов в JVM
Все в Java — классы, и все Java-приложения состоят из классов. Любое приложение может состоять из одного или многих тысяч классов. Чтобы запустить Java-приложение, JVM должна загрузить скомпилированные .class-файлы в контекст — например, в сервер, где они будут доступны. JVM зависит от своего загрузчика класса для корректного выполнения этой функции.
Загрузчик классов Java является частью JVM — он загружает классы в память и делает их доступными для выполнения. Загрузчик классов использует технику ленивой загрузки (lazy-loading) и кэширование, чтобы сделать загрузку классов максимально эффективной. При этом использование таких методов считается достаточно простым процессом.
Все виртуальные машины Java включают в себя загрузчики классов. Спецификация JVM описывает стандартные методы для запроса и управления загрузчиком во время работы, но за выполнение этих возможностей отвечает конкретная реализация JVM. С точки зрения разработчика, механизмы, лежащие в основе загрузчика классов, обычно представляют собой черный ящик.
Механизм выполнения в JVM
После того, как загрузчик классов завершил свою работу, JVM начинает выполнять код каждого класса. Механизм выполнения — компонент JVM, который обрабатывает функции, и он необходим для корректной работы любой виртуальной машины Java.
Выполнение кода включает управление доступом к системным ресурсам. Механизм выполнения JVM находится между работой программы, с ее запросами на файловые, сетевые ресурсы и ресурсы памяти, и операционной системой, которая предоставляет эти ресурсы.
Управление системными ресурсами
Системные ресурсы могут быть разделены на две больших категории: память и все остальное.
JVM отвечает за очистку неиспользуемой памяти, при этом сборщик мусора — это механизм, который и осуществляет этот процесс. JVM также отвечает за распределение и поддержание ссылочной структуры, которую любой разработчик принимает как само собой разумеющееся. Например, механизм выполнения JVM отвечает за то, что при использовании ключевого слова new происходит запрос к операционной системе на выделение памяти.
Помимо памяти, механизм выполнения управляет ресурсами файловой системы и сети. Поскольку JVM совместима с различными операционными системами, то эта задача считается достаточно сложной. Помимо потребностей каждого приложения в ресурсах, механизм выполнения должен корректно работать с каждой операционной системой.
Эволюция JVM: прошлое, настоящее, будущее
В 1995 году разработчики JVM представили две революционные концепции, которые с тех пор стали стандартом в разработке: «Написал один раз, запускай везде» и автоматическое управление памятью. В то время совместимость софта была смелой концепцией, но сейчас это стало нормой. Точно так же, как современное поколение живет с автоматической сборкой мусора.
Можно сказать, что если Джеймс Гослинг и Брендан Эйх изобрели современное программирование, то тысячи других разработчиков усовершенствовали и развили их идеи в последующие десятилетия. Изначально виртуальная машина Java предназначалась только для Java, но сегодня она эволюционировала до поддержки многих языков программирования, включая Scala, Groovy и Kotlin.
Изучайте Java на Хекслете
Вступайте в профессию и изучайте один из самых востребованных в энтерпрайзе языков программирования.
Как работает Java? Краткое руководство
Если вы новичок в программировании и не знакомы с концепцией того, что такое программа, давайте начнем с нее. Согласно Techopedia, « Программное обеспечение обычно определяется как набор инструкций или набор модулей или процедур, которые позволяют выполнять определенные операции на компьютере. » Инструкции программы могут быть написаны на нескольких языках, включая, конечно же, Java. Но как именно работает Java?
Как работает Java (в двух словах)
Java работает, сначала компилируя исходный код в байт-код. Затем байт-код может быть скомпилирован в машинный код с помощью виртуальной машины Java (JVM). Байт-код Java может работать на любом устройстве с JVM, поэтому Java известен как язык « написания один раз, запуск где угодно ».
Конечно, это немного упрощенная версия того, как работает Java. На самом деле это намного больше. С технической точки зрения, при написании простой программы «Hello World» на Java данные делают несколько остановок, прежде чем они закончатся текстом на экране. Более подробное объяснение дает почти комично мой сокурсник по университету; Сохаил Ахмед Ансари.
Sohail делает еще один шаг вперед и объясняет не только то, как работают Java-программы, но и то, как программы работают в целом при взаимодействии с операционной системой (ОС). Последняя часть его объяснения верна для всех программ. Однако, чтобы по-настоящему понять, как работает Java и в чем ее уникальность, давайте сначала посмотрим, как работает другой язык.
Как работает C++
Когда в 1995 году была создана Java, она была создана по образцу C++. В этих языках есть некоторые сходства и некоторые различия. Конечно, синтаксис другой. Однако основное отличие заключается в том, как выполняется код. В отличие от Java, которая компилируется в байт-код, который затем может работать на любом устройстве с JVM, C++ компилируется непосредственно в машинный код. Вот почему Java известен как «Напиши один раз, работай где угодно».
Когда программа, написанная на C++, компилируется, этот скомпилированный код может работать только в этой среде. Чтобы та же программа могла работать в другой среде, исходный код должен быть перенесен в эту среду, а затем скомпилирован. Это одно из преимуществ Java по сравнению с другими языками. Давайте взглянем на JVM Java и посмотрим, что делает ее такой особенной.
JVM и машинный код
Мы уже установили, что C++ работает только в той среде, в которой он был скомпилирован. Виртуальная машина Java обеспечивает среду выполнения, необходимую для работы Java практически на любом компьютере. После компиляции Java-программы в байт-код ее можно интерпретировать в машинный код с помощью JVM.
Это работает таким образом, потому что большинство компьютеров имеют свой собственный машинный код. Машинный код, если вы еще не знакомы, это код, который может понять только компьютер. Он отличается от кода высокого и среднего уровня, который мы используем для написания программы. Машинный код также называют ассемблером или низкоуровневым кодом. Чем ниже уровень, тем ближе код к реальным инструкциям для процессора. Чем он выше, тем ближе он к тому, что может понять человек.
Объектно-ориентированное программирование
До сих пор я описывал, как Java работает за кулисами. Однако также важно понимать, как Java работает во внешнем интерфейсе. Известно, что Java является языком объектно-ориентированного программирования (ООП) общего назначения. Термин «общего назначения» просто относится к обширным возможностям Java. Есть не так много вещей, которые вы не можете сделать с Java. С другой стороны, объектно-ориентированный относится к тому факту, что практически все в Java является объектом.
Я не буду здесь слишком глубоко погружаться в ООП. Тем не менее, я кратко опишу в общих чертах, что такое объект. Объект в ООП подобен объекту в реальной жизни. Это может относиться к человеку, месту или предмету. Точно так же, как у меня есть две руки и две ноги, которые вы могли бы назвать характеристиками, если бы я был объектом в программе, их можно было бы назвать типами данных. Кроме того, точно так же, как я могу что-то делать в реальной жизни, объект, представляющий меня в программе, тоже может что-то делать. Эти действия являются типами операций, также известными как функции. Объекты имеют состояния (атрибуты или характеристики), поведения (функции) и личности (имя объекта).
https://www.youtube.com/watch?v=0NPR8GFHNmEВидео не может быть загружено, так как JavaScript отключен: Java — основы ООП 1/5 (класс и объект) (https://www.youtube.com/ watch?v=0NPR8GFHNmE)
Классы, методы и переменные Java
При написании новой программы на Java необходимо объявить имя класса. Как новичок, это все, что вам нужно знать. Однако после того, как вы освоите основы переменных и методов, вам придется глубже изучить ООП, классы и некоторые более сложные темы. А пока я скажу вам, что классы по сути являются объектами. Или, скорее, они являются чертежами объектов, в которых находится все, что их определяет. Переменные относятся к состоянию объекта, а методы относятся к поведению.
Когда вы начинаете изучать Java, вы, скорее всего, будете использовать только один объект: основной класс. Однако после того, как вы изучите основы и достигнете ООП, у вас будет несколько классов, взаимодействующих друг с другом. Помните, что метод объекта относится к его поведению. Следовательно, когда объекты взаимодействуют друг с другом, они просто вызывают метод указанного объекта для такого поведения.
Статьи по теме
Как работает Java
Как работает Java
Эта страница является необязательной для чтения. Если вы изначально найдете терминологию
предчувствие, вы можете прекратить чтение. Прочтите страницу еще раз позже в
срок.
Некоторые студенты хотят узнать немного больше о языке программирования Java.
и эта страница — самое простое объяснение, которое я могу сформулировать. Учебник
не дает подобного объяснения.
Прежде чем понять, как работает Java, вам сначала нужно изучить некоторые
терминологии, связанной с более ранними языками программирования.
Краткая история программирования
Языки Работа
Все высокоуровневое (также называемое третьего поколения ) программирование
языки позволяют писать программы на языке, похожем (хотя во многом
проще), чем естественный язык.Программа высокого уровня называется источником .
код .Низкоуровневый язык программирования ближе к тому, что
имеет смысл для компьютера. Детали для низкоуровневых языков не важны
на вводных курсах CS.Компиляторы
Большинство компьютерных языков используют формат «компиляция-связывание-выполнение».
Вы начинаете с исходного кода
и компилятор преобразуют эту программу в низкоуровневую
программа.В большинстве скомпилированных языков файл, содержащий результирующий низкоуровневый
код называется файлом объекта . Коллекция объектов
файлы связаны вместе, чтобы создать исполняемый
файл (т. е. операционная система может загрузить исполняемый файл в оперативную память для запуска
программа). Другой термин для исполняемого файла — «(перемещаемая) машина».
код».Объектный файл не может быть легко прочитан человеком, но он не может быть запущен
на компьютере.Например, если ваша программа извлекает квадратный корень из числа,
ваша программа будет опираться на математическую программу (предоставленную математическим
библиотека языка), которая фактически определяет, как вычислить квадрат
корень. Объектный файл для программы будет ссылаться на квадратный корень, но
не будет кода, объясняющего, как работает вычисление квадратного корня.
Точно так же, когда вы начнете решать более крупные проблемы, вы, скорее всего, разделите
ваш проект в несколько программ, которые общаются.Процесс связывания соединяет имеющиеся у вас объектные файлы
созданный вместе с другими ранее существовавшими объектными файлами для формирования исполняемого
файл. Компоновщик выполняет эту работу. Вы не должны ожидать найти
ссылка
ошибки
, пока вы не начнете писать большие программы, состоящие из нескольких частей;
ошибки связи возникают, когда объектные файлы для вашей программы не полностью
общаться адекватно.Переводчики
Существует меньшее количество языков (Lisp и Scheme
самый знаменитый; CMU использует ML в 15-212), что позволяет избежать «компилировать-связывать-выполнять».
последовательность и вместо этого попытаться выполнить преобразование «на лету» (также называемое
«по мере необходимости»).Другими словами, интерпретируемый язык принимает каждый высокоуровневый
оператор, определяет его низкоуровневую версию и выполняет (при компоновке
если нужно) результат. Это делается для каждого оператора подряд (до
даже рассматривается следующее заявление высокого уровня).
По аналогии с иностранными языками компилятор выступает в роли переводчика (скажем,
кто-то, кто переводит книгу), а переводчик действует как переводчик.
При отладке программ вы не заметите большой разницы между
компиляторы и интерпретаторы, потому что исполняемый файл необходимо регенерировать
при каждом изменении исходного кода. Однако после завершения отладки
исполняемый файл, созданный компилятором, будет работать намного быстрее, чем аналогичный
кусок исходного кода, который всегда должен проходить через свой интерпретатор. С использованием
аналогия, чтение перевода стихотворения всегда будет «быстрее», чем
приходится интерпретировать стихотворение на лету каждый раз, когда вы его читаете.
Однако у интерпретируемых языков есть преимущества. В искусственных
интеллекту, интерпретируемые языки предпочтительнее, поскольку программы могут иметь
адаптироваться к новым раздражителям. Кроме того, как правило, проще построить прототип.
программа с помощью интерпретатора. Многие интерпретируемые языки также предоставляют
«режим компиляции» для создания исполняемых файлов, которые будут работать примерно так же быстро, как
исполняемый файл, созданный компилятором.
Как работает Java
Java — первый полноценный язык, который не интерпретируется по-настоящему
ни компилируется; вместо этого используется комбинация двух форм. Этот способ
имеет преимущества, которых не было в более ранних языках.
Независимость от платформы
Чтобы понять главное преимущество Java, вам нужно узнать о
платформы . В большинстве языков программирования компилятор (или интерпретатор)
генерирует код, который может выполняться на определенных цель машина. За
Например, если вы скомпилируете программу на C++ на компьютере с Windows, исполняемый файл
файл можно скопировать на любой другой компьютер, но он будет работать только на другом
Компьютеры с Windows, но не другие компьютеры (например, Mac или Linux).
Платформа определяется целевой машиной (вместе с ее операционной
система). Для более ранних языков разработчикам языков нужно было создать специализированный
версия компилятора (или интерпретатора) для каждой платформы. Если вы написали
программу, которую вы хотели сделать доступной на нескольких платформах, вы,
как программисту, придется проделать немало дополнительной работы.
Вам придется создать несколько версий исходного кода для
каждой платформы.
Java удалось устранить проблему с платформой для программистов высокого уровня
(например, вы), потому что он реорганизовал компиляцию-связку-выполнение
последовательность на базовом уровне компилятора. Детали сложны
но, по сути, разработчики языка Java изолировали эти программные
проблемы, которые зависят от платформы и разработанных низкоуровневых средств
абстрактно относиться к этим вопросам. Следовательно, компилятор Java не
создать объектный файл, но вместо этого он создает байт-код
файл
который, по сути, является объектным файлом для виртуального
машина . На самом деле, компилятор Java часто называют
Компилятор JVM (для виртуальной машины Java).
Следовательно, вы можете написать программу на Java (на любой платформе) и использовать
компилятор JVM (называемый javac)
для создания файла байт-кода (файлы байт-кода используют расширение
.учебный класс).
Этот файл байт-кода можно использовать на любой платформе (с установленной Java).
Однако байт-код не является исполняемым файлом. Чтобы выполнить байт-код
файл, вам действительно нужно вызвать интерпретатор Java (называемый java).
Каждая платформа имеет свой собственный интерпретатор Java, который автоматически обращается к
проблемы, связанные с платформой, которые больше нельзя откладывать. Когда
специфические для платформы операции требуются байт-кодом, интерпретатором Java
ссылки в соответствующем коде, специфичном для платформы.
Подводя итог тому, как работает Java (для достижения независимости от платформы),
подумайте о цикле компиляция-связывание-выполнение. В более ранних языках программирования
цикл более точно определяется как «компиляция-ссылка, затем выполнение». В Яве,
цикл ближе к « compile then link-execute «.
Как и в случае с интерпретируемыми языками, Java-программы можно запускать
быстрее за счет компиляции байт-кода в исполняемый файл; недостатком является
что такие исполняемые файлы будут работать только на той платформе, на которой они созданы.
Другие преимущества Java
Большинство других функций Java ранее существовало в различных
другие языки программирования (но не все сразу). Большинство объяснений
из этих преимуществ (например, распределенное программирование, многопоточность, безопасность)
выходят далеко за рамки этого курса. Однако есть две особенности
что я кратко остановлюсь.
Еще одна функция, появившаяся в языке Java, — это возможность
для написания специальных Java-программ (называемых апплеты ), которые разработаны
для работы во всемирной паутине. Вы можете написать Java-апплет и поместить
байт-код на веб-странице; если кто-то с веб-браузером с поддержкой Java пойдет
на вашу веб-страницу, байт-код этого апплета будет загружен в браузер
компьютер и выполняется в веб-браузере. Конечно, это не
быть возможным без независимости от платформы. Эта функция оказала большое влияние
о быстром распространении Java и многих инструкторах (включая меня)
преподавал программирование с использованием программ на основе апплетов. Однако для разнообразия
по причинам, я решил отложить обсуждение апплетов (и не только
как правило, графические пользовательские интерфейсы) до конца курса.
Java также является одним из первых языков, который « основан на библиотеке »
в том, что разработчики языка включили большое количество ранее существовавших
программы. Программист может подключить свою программу к этим универсальным
программы по мере необходимости. Это освобождает время программиста, поскольку он не
нужно написать как можно больше кода. Мы начнем изучать эту библиотеку под названием
API
(интерфейс прикладного программирования) после того, как мы изучим существенное количество
самого языка Java.
Java против C#
Последний язык Microsoft, C# (разновидность C/C++),
был первым основным языком после Java, который имел компиляцию, а затем компоновку-выполнение.
цикл. C# также решил большинство других проблем, которые были связаны с Java.
преимущества, а C# представил и другие преимущества.