JVM, JDK, JRE
JVM - Java Virtual Machine — среда (виртуальная), в которой выполняется скомпилированный код.
JRE - Java Runtime Environment. Просто пакет, который включает в себя JVM — минимальный набор библиотек для работы программ, а также браузерный плагин, где выполняются апплеты.
JDK - Java Development Kit - это полноценный набор библиотек и инструментов для создания, компилирования и дебага программ, который включает в себя jre.

Как и другие языки программирования, элементы Java существуют не сами по себе. Они, скорее действуют совместно, образуя язык в целом. Но их взаимосвязь может затруднять описание ГОJJ'О одного аспекта jаvа, не затрагивая ряда других. Зачастую для понимания одного языкового средства необходимо владеть другим. Поэтому в этой главе представлен краткий обзор ряда основных языковых средств Java. Приведенный в данной главе материал послужит отправной точкой создания и понимания простых программ. Большинство рассмотренных в этой главе вопросов более подробно будут обсуждаться в остальных главах.
Java является объектно-ориентированным языком программирования
Объектно-ориентированное программирование (ООП) составляет основу Java. По существу, все программы Java являются в какой-то степени объектно-ориентированными. Язык Java связан с ООП настолько тесно, что, прежде чем приступить к написанию на нем простейших программ, следует вначале ознакомиться с основными принципами ООП. Поэтому начнем с рассмотрения теоретических вопросов.
Две методики
Все компьютерные программы состоят из двух элементов: кода и данных. Кроме того, программа концептуально может быть организована вокруг своего кода или своих данных. Иными словами, организация одних программ определяется тем, что происходит, а других - тем, на что оказывается влияние. Существуют две методики создания программ. Первая из них называется моделью. Модель ориентирована на процессы и характеризует программу как последовательность линейных шагов (т.е. кода). Ее можно рассматривать в качестве кода, воздействующего на данные. Такая модель довольно успешно применяется в процедурных языках типа С. Однако, как отмечалось в Главе 1, из-за увеличения размеров и сложности программы, данный подход порождает ряд трудностей.
С целью преодоления увеличения сложности программ, начата разработка подхода, называемого "объектно-ориентированным программированием". Объектно-ориентированное программирование позволяет организовать программу вокруг ее данных (объектов) и определенных интерфейсов. Объектно-ориентированную программу можно охарактеризовать как данные, управляющие доступами к полю. Далее вы узнаете, что, передавая функции управления данными, можно получить несколько организационных преимуществ.
Абстракция
Важным элементом ООП является абстракция. Человеку свойственно представлять сложные явления и объекты, прибегая к абстракции. Например, люди представляют себе автомобиль не в виде набора отдельных деталей, а в виде совершенно определенного объекта, имеющего свое особое действие. Эта абстракция позволяет не задумываться о сложности деталей, составляющих автомобиль, скажем, при поездке в магазин. Можно не обращать внимания на работу двигателя, коробки передач и тормозной системы. Вместо этого, объект можно использовать как единое целое. Эффективным средством применения абстракции служат иерархические классификации. Это позволяет упрощать семантику сложных систем, разбивая их на более управляемые части. Внешне автомобиль выглядит единым объектом. Но стоит заглянуть внутрь, как становится ясно, что он состоит из нескольких подсистем: рулевого управления, тормозов, аудиосистемы, привязных ремней, обогревателя, навигатора и т.п. Каждая из этих подсистем, в свою очередь, собрана из более специализированных узлов. Например, аудиосистема состоит из радиоприемника, проигрывателя, компакт-дисков и/или аудиокассет.
Суть всего сказанного состоит в том, что структуру автомобиля (или любой другой сложной системы) можно описать с помощью иерархических абстракций. Иерархические абстракции сложных систем применимы и к компьютерным программам. Благодаря абстракции данные традиционной, ориентированной на процессы программы можно преобразовать в составляющие ее объекты, а последовательность этапов процесса - в совокупность сообщений, передаваемых между этими объектами.
Таким образом, каждый из этих объектов описывает свое особое поведение. Эти объекты можно считать конкретными сущностями, реагирующими на сообщения, в которых указано выполнить конкретное действие. В этом, собственно, и состоит вся суть ООП. Принципы ООП лежат как в основе языка Java, так и в восприятии мира человеком. Важно понимать, каким образом эти принципы реализуются в программах . Далее указано, что ООП является еще одной, более эффективной и естественной методикой создания программ, которые, в свою очередь, терпят неизбежные изменения в жизненном цикле программного проекта, а именно: зарождение общего замысла, развитие и созревание. Например, при наличии определенных объектов и ясных, надежных интерфейсов с этими объектами, можно безбоязненно и без особого труда извлекать или заменять части старой системы.
Три принципа ООП
Все языки объектно-ориентированного программирования представляют собой механизмы, облегчающие реализацию объектно-ориентированной модели. Этими механизмами являются: инкапсуляция , наследование и полиморфизм. Рассмотрим данные принципы ООП по отдельности.
Инкапсуляция
Механизм, манипулирующий и защищающий от внешнего вмешательства и злоупотреблений код и данные, называется инкапсуляцией. Инкапсуляцию можно считать защитной оболочкой , которая предотвращает произвольный доступ со стороны другого кода, находящегося снаружи оболочки. Доступ к коду и данным, находящимся внутри оболочки, строго контролируется определенным интерфейсом.
Приведем аналог из реального мира и рассмотрим автоматическую коробку передач автомобиля. Она инкапсулирует большое количество данных об автомобиле, в том числе: скорость ускорения, крутизну поверхности , по которой совершается движение, а также положение рычага переключения скоростей. Пользователь (водитель) может оказывать влияние на эту сложную инкапсуляцию только одним способом: перемещая рычаг переключения скоростей. На коробку передач нельзя воздействовать с помощью индикатора поворота или дворников, т.к. рычаг переключения скоростей является строго определенным и единственным интерфейсом с коробкой передач. Происходящее внутри коробки передач не влияет на окружающие объекты. Например, переключение передач не включает фары. Функция автоматического переключения передач инкапсулирована, поэтому десятки изготовителей автомобилей могут реализовать ее как угодно. Однако, с точки зрения водителя, все коробки передач работают одинаково.
Аналогичный принцип можно применять и в программировании. Сильная сторона инкапсулированного кода состоит в следующем: всем известно, как получить доступ к нему, и, следовательно, его можно использовать независимо от подробностей реализации и не опасаясь неожиданных результатов.
Основу инкапсуляции в Java составляет класс. Подробнее классы будут рассмотрены в следующих главах, перед этим предлагаем ознакомиться с их кратким описанием. Класс определяет структуру и поведение (данные и код), которые будут совместно использоваться набором объектов. Каждый объект данного класса содержит структуру и поведение, которые определены классом, подобно тому как объект был бы "отлит" в форме класса. Поэтому иногда объекты называют "экземплярами класса".
Таким образом, класс — это логическая конструкция, а объект — ее физическое воплощение. При создании класса определяются код и данные, которые, соответственно, образуют класс. Совместно эти элементы называются членами класса. В частности, определенные в классе данные называются переменными членами и или переменными экземпляра, а код, оперирующий данными, — методами-членами или просто методами. То, что программирующие нa Java называют "методами", программирующие на С/С++ называют "функциями". В программах, правильно написанных на Java, методы определяют, каким образом используются переменные-члены. Это означает, что поведение и интерфейс класса определяются методами, оперирующими данными его экземпляра. Поскольку назначение класса состоит в инкапсуляции сложной структуры программы, существуют механизмы сокрытия сложной структуры реализации в самом классе.
Каждый метод или переменная в классе могут быть помечены как закрытые или открытые. Открытый интерфейс класса представляет все, что должны или могут знать внешние пользователи класса. Закрытые методы и данные могут быть доступны только для кода, который является членом данного класса. Следовательно, любой другой код, не являющийся членом данного класса, не может получать доступ к закрытому методу или переменной. Закрытые члены класса доступны другим частям программы только через открытые методы класса, и, благодаря этому, исключается возможность выполнения неправомерных действий. Это означает, что открытый интерфейс должен быть тщательно спроектирован и не должен раскрывать лишние подробности внутреннего механизма работы класса.
Наследование
Процесс, в результате которого один объект получает свойства другого, называется "наследованием". Это очень важный принцип ООП, поскольку наследование обеспечивает принцип иерархической классификации. Как отмечалось ранее, большинство знаний становятся понятными благодаря иерархической (т.е. нисходящей) классификации. Например, золотистый ретривер - часть классификации собак, которая относится к классу млекопитающих, который, в свою очередь, — к еще большему классу животных. Без иерархий каждому объекту необходимо было бы явно определять свои характеристики. Но, благодаря наследованию, объект должен определять только те характеристики, которые делают его особенным в классе. Объект может наследовать общие атрибуты родительского объекта.
Таким образом, механизм наследования позволяет сделать один объект частным случаем более общего случая. Рассмотрим этот механизм подробнее. Как правило, большинство людей воспринимают окружающий мир в виде иерархически-связанных между собой объектов, подобных животным, млекопитающим и собакам. Если потребуется привести абстрактное описание животных, можно сказать, что они обладают определенными свойствами: размером, интеллектом и костной системой. Животным присущи также определенные особенности поведения: они едят, дышат и спят. Такое описание свойств и поведения составляет определение класса "животные". Если бы потребовалось описать более конкретный класс животных, например, млекопитающих, следовало бы указать более конкретные свойства, в частности, тип зубов и молочных желез. Такое определение называется подклассом животных, которые относятся к суперклассу (родительскому классу) млекопитающих. А поскольку млекопитающие — лишь более точно определенные животные, то они наследуют все свойства животных. Подкласс низшего уровня иерархии классов наследует все свойства каждого из родительских классов. Наследование также связано с инкапсуляцией. Если отдельный класс инкапсулирует определенные свойства, то любой его подкласс будет иметь те же самые свойства, а также любые дополнительные, определяющие его специализацию. Благодаря этому ключевому принципу, сложность объектно-ориентированных программ нарастает в арифметической, а не геометрической прогрессии. Новый подкласс наследует атрибуты всех своих родительских классов и поэтому не содержит непредсказуемые взаимодействия с большей частью остального кода системы.
Полиморфизм
Полиморфизм (от греч. "много форм") — это принцип ООП, позволяющий использовать один и тот же интерфейс для общего класса действий. Каждое действие зависит от конкретной ситуации. Рассмотрим в качестве примера стек, действующий как список обратного магазинного типа. Допустим, программе требуются стеки трех типов: для целочисленных значений, для числовых значений с плавающей точкой и для символов. Алгоритм реализации каждого из этих стеков остается неизменным, несмотря на отличия в данных, которые в них хранятся. В языке, не являющемся объектно-ориентированным, для обращения со стеком пришлось бы создавать три разных ряда служебных программ под отдельными именами. А в Java, благодаря принципу полиморфизма, для обращения со стеком можно определить общий ряд служебных программ под одними и теми же общими именами. В более общем смысле, принцип полиморфизма нередко выражается фразой "один интерфейс, несколько методов". Это означает, что можно разработать общий интерфейс для группы связанных вместе действий. Такой подход позволяет уменьшить сложность программы, поскольку один и тот же интерфейс служит для указания общего класса действий. А выбор конкретного действия (т.е. метода) делается применительно к каждой ситуации и входит в обязанности компилятора. Это избавляет программиста от необходимости делать такой выбор вручную. Ему нужно лишь помнить об общем интерфейсе и правильно применять его. Если продолжить аналогию с предыдущим примером, то можно сказать, что собачье обоняние — полиморфное свойство. Если собака почувствует запах кошки, она залает и погонится за ней . А если собака почувствует запах корма, то у нее начнется слюноотделение, и она поспешит к своей миске. В обоих случаях действует одно и то же чувство - обоняние. Отличие лишь в запахе, т.е. в типе данных, воздействующих на нос собаки! Этот общий принцип можно реализовать, применив его к методам в программе нa java.
Первый пример простой программы
А теперь, когда разъяснены важнейшие основы объектно-ориентированного характера Jаvа, рассмотрим несколько практических примеров программ, написанных на этом языке. Начнем с компиляции и запуска короткого примера программы. Оказывается, что эта задача не так проста, как может показаться на первый взгляд.
public class Example{
public static void main(String[]args) {
System.out.println("TEST");
}
}
Ввод кода программы
Для большинства языков программирования, имя файла, который содержит исходный код программы, не имеет значения. Но в Java дело обстоит иначе. Прежде всего, следует твердо усвоить, что исходному файлу очень важно присвоить имя. В данном примере исходному файлу должно быть присвоено Example.java, т.к. в Java исходный файл официально называется единицей кoмпиляции. Он, среди прочего, представляет собой текстовый файл, содержащий определения одного или нескольких классов (для начала будем использовать исходные файлы , содержащие только один класс). Компилятор Java требует, чтобы исходный файл имел расширение java. Как следует из исходного кода примера программы, определенный в ней класс также называется Example, т.к. в Java код целиком должен размещаться в классе. По принятому соглашению, имя главного класса должно совпадать с именем файла, содержащего исходный код программы. Кроме того, написание имени исходного файла должно полностью соответствовать имени главного класса, включая строчные и прописные буквы. Дело в том, что в коде Java учитывается регистр символов. На первый взгляд, соглашение о строгом соответствии имен файлов и классов может показаться произвольным. Но на самом деле, оно упрощает сопровождение и организацию программ.
Компиляция программы
Чтобы скомпилировать программу Example, запустите компилятор ( javac), указав имя исходного файла в командной строке следующим образом:
javac Ехаmрlе.java
Компилятор javac создаст файл Example.class, содержащий версию байт-кода. Как пояснялось ранее, байт-код Java является промежуточным представлением программы, содержащим инструкции, которые будет выполнять виртуальная машина JVМ . Следовательно, компилятор javac выдает результат, который не является непосредственно исполняемым кодом.
Для запуска программы выполните команду:
java Example
JVM

На рисунке байт-код передается в JVM.
После этого, данный код проходит этап валидации. В случае успешной валидации, происходит загрузка классов загрузчиком и запускается полный цикл.
JVM взаимодействует с ОС через нативные методы
Детальную информацию о работе JVM можно найти по спецификации виртуальной машины Java.
Ссылка на версию 8: https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf