В. Цишевский, Jet Infosystems
Преамбула
На сегодняшний день создание программного обеспечения представляет собой чрезвычайно тяжелое занятие. Трудности связаны с разнообразием архитектур машин, операционных систем, графических оболочек и т.д.. Кроме того, ваши приложения должны работать в расп
Предлагаемый фирмой Sun Microsystems подход, а именно система программирования на основе языка Java(TM) обладает следующими характеристиками:
Основы проекта Java. Немного истории
Целью проекта было создание небольшой, надежной, переносимой и распределенной системы реального времени. Исходно в качестве языка планировалось использование языка программирования С++, но постепенно связанные с ним трудности привели к необходимости созд
Стремительный рост сетевых технологий привел к необходимости нового взгляда на процесс создания и распределения приложений. Современные приложения должны быть безопасны, высокопроизводительны, работать в распределенной среде на множестве машин различной
Требования к переносимости заставили отказаться от традиционного способа создания и доставки бинарных файлов, содержащих машинные коды и, следовательно, привязанных к определенной платформе. Сегодня, чтобы выжить в этих джунглях из архитектур процессоров
Созданная система разработки Java удовлетворяет всем этим требованиям, а следовательно:
Свойства Java, краткий обзор
Java проста, объектно ориентированна и знакома
Система Java создана на основе *простого* языка программирования, техника использования которого близка к общепринятой и обучение которому не требует значительных усилий.
Java как язык программирования является объектно ориентированной с момента основания. Кроме того программист с самого начала обеспечивается набором *стандартных* библиотек, обеспечивающих функциональность от стандартного ввода/вывода и сетевых протоколов
Несмотря на то, что язык С++ был отвергнут, синтаксис языка Java максимально приближен к синтаксису С++. Это делает язык знакомым широкому кругу программистов. В то же время из языка были удалены многие свойства, которые делают С++ излишне сложным для по
Надежность и безопасность
Java существенно облегчает создание надежного программного обеспечения. Кроме исчерпывающей проверки на этапе компиляции, система предусматривается анализ на этапе выполнения. Сам язык спроектирован так, чтобы вырабатывать у программиста привычку писать
В силу того, что Java предназначена для работы в распределенной среде, безопасность становится чрезвычайно важной проблемой. Требования безопасности определяют многие черты как языка, так и реализации всей системы.
Независимость от архитектуры и переносимость.
Компилятор Java производит байт-коды, т.е. модули приложения имеют архитектурно-независимый формат, который может быть проинтерпретирован на множестве разнообразных платформ. Это уже не исходные тексты, но еще не платформно-зависимые машинные коды.
Следующий шаг -- "замораживание" стандарта на формат основных встроенных типов данных. Программа, созданная на одной платформе, работает на всех остальных.
Этот стандарт фиксирован в документе, описывающем Java Virtual Machine. Стандарт может быть реализован на любой аппаратно-программной платформе, поддерживающей многопотоковость.
Производительность
Схема работы системы и набор байт-кодов виртуальной машины Java таковы, что позволяют достичь высокой производительности на этапе выполнения программы:
Базовая система Java
Опыт показывает, что отсутствие стандартных базовых библиотек для языка С++ чрезвычайно затрудняет работу с ним. В силу того, что любое нетривиальное приложение требует наличия некоторого набора базовых классов, разработчикам приходится пользоваться разл
Полная система Java включает в себя готовый набор библиотек, который можно разбить на следующие пакеты:
Результат -- новый подход к распределенным вычислениям
Каждая из перечисленных характеристик по отдельности может быть найдена в уже существующих программных пакетах. Новым является соединение их в стройную непротиворечивую систему, которая должна стать всеобщим стандартом.
На сегодняшний день наиболее популярными языками программирования являются С и С++. Из них двоих лишь С++ претендует на объектную ориентацию. Характеристики этого языка складывались в ходе длинной истории его развития, причем довольно хаотично, каждое но
Java представляет собой новую точку отсчета в программном обеспечении. Разработчики языка взяли за основу С++, затем методично удалили из него черты, которые:
Основные свойства языка программирования Java
Встроенные (примитивные) типы данных
В языке Java, так же как и в С++, существует набор встроенных типов данных, которые (так же как и в С++) не являются объектами. Набор их также сходен с набором базовых типов С++ за некоторыми исключениями.
Point myPoints[];резервирует ссылку на массив, а не место под реальный объект. Сам массив может быть затем создан выполнением
myPoints = new Point[10];а его элементы заполнены операцией типа:
myPoints[2] = new Point();Размер массива может быть получен во время выполнения программы:
howMany = myPoints.length;Значение индекса проверяется при каждом обращении, при ошибке возбуждается исключительная ситуация.
String hello = "Hello world!";Ссылка hello инициируется объектом класса String на основе представления "Hello world!" в кодировке Unicode.
System.out.println("There are" + num + "characters in the file.");Multi-Level Break
test: for(int i = 0; i < 10; i++) for(int j = 0; j < 10; j++) if( i > 3) break test;Управление памятью, сборка мусора
Свойства, присутствующие в С и С++, и удаленные из Java
Конструкция typedef, препроцессор
Конструкция typedef была унаследована С++ из С. Из Java она выброшена совсем.
Необходимость в макропроцессоре также во многом отпала при написании программ на С++. Почти все, для чего использовались макрорасширения, можно было сделать более элегантным и надежным образом, используя конструкции самого языка.
Система неявно поощряла создание каждым программистом своего собственного подмножества языка, неизвестного остальному миру. По мере разрастания кодов увеличивается тот смысловой контекст, в котором компилятор интерпретирует каждую строку программы. Уже в
Единственная оставшаяся важная функция препроцессора -- позволить включение в программу файлы-заголовки с описаниями классом. Эта операция может быть выполнена более просто и эффективно, если позволить компилятору читать подготовленные бинарные файлы с о
Все эти соображения позволили полностью исключить необходимость использования текстового препроцессора в языке Java.
Struct и union
Структуры не имеют смысла в Java, их роль полностью выполняют классы. Использование конструкций типа union для типизованных объектов также больше не нужно -- язык позволяет определить тип объекта при исполнении программы.
Функции
В этом смысле Java чисто объектно-ориентированная система. Функции и процедуры, не привязанные к контексту какого-либо объекта, больше не присутствуют в системе. В ситуации, когда функция логически не привязана к определенному экземпляру класса, она може
Множественное наследование
Последовательная реализация концепции множественного наследования в С++ привела к существенным сложностям как в создании компиляторов, так и в использовании его (множественного наследования) в программах. В качестве альтернативы Java использует понятие и
То, чего интерфейс содержать не может -- это реализации методов или изменяемые поля данных. Классы, которые объявлены, как реализующие тот или иной интерфейс, обязаны реализовать все методы, объявленные в интерфейсе.
Goto
см. выше описание операторов continue и break с меткой.
Перегрузка операторов
Опыт использования перегруженных операторов в С++ показывает, что они имеют смысл в довольно ограниченном наборе ситуаций. С другой стороны, злоупотребление этим свойством может сделать программу абсолютно непонятной. Единственное "встроенное" в язык Jav
Автоматическое преобразование типов
В языке Java запрещено автоматическое преобразование типов, широко используемое (и рекомендуемое) в С++. Чтобы преобразовать элемент одного типа в другой, необходимо указать это явно, например
int myInt; double myFloat = 3.14159; myInt = myFloat; // допустимо в С++, недопустимо в Java myInt = (int)myFloat; // допустимо в JavaИсключение составляет преобразование между встроенными численными типами без потери информации.
Итоги
Итак, мы показали два из основных свойства языка программирования Java
Система Java создавалась объектно ориентированной с самого начала. Объектно-ориентированная парадигма наиболее удобна при создании программного обеспечения типа клиент-сервер, а также для организации распределенных вычислений.
Одна из черт, присущих объектам, заключается в том, что объекты обычно переживают процедуру, их создающую. Они затем могут перемещаться по сети, храниться в базах данных и т.д.
Идейными наследниками Java являются такие языки, как C++, Eiffel, Smalltalk и Objective C. За исключением примитивных типов данных, практически все в языке является объектом.
Основные требования к объектно-ориентированной системе
Объектная модель Java
Классы
Класс есть языковая конструкция, определяющая поля данных объектов данного класса (instance variables) и их поведение (methods). Практически класс в Java сам по себе не является объектом. Это лишь шаблон, который определяет, из каких частей будет состоят
Простейший пример описания класса
class Point extends Object { public double x; public double y; }Создание объекта определенного класса
Point myPoint; // объявление переменной типа Point myPoint = new Point(); // инициализацияа обратиться к полям данных следующим образом
myPoint.x = 10.0; myPoint.y = 25.7;Конструкторы
class Point extends Object { Point() { x = 0.0; y = 0.0; } Point(double x, double y) { this.x = x; this.y = y; } public double x; public double y; }а использованы они могут быть следующим образом
Point a; Point b; a = new Point(); b = new Point(1.0, 2.0);обратите внимание на имя this в определении конструктора с аргументами. Оно используется для обозначения самого объекта, в методе которого мы находимся, в тех случаях, когда ссылка на этот объект не подразумевается неявно.
Pclass Point extends Object { private double x; private double y; public void setX(double x) { this.x = x; } public void setН(double y) { this.y = y; } ... }Мы теперь сделали поля x и y недоступными извне класса, но для изменения их состояния предусмотрели специальные методы setX и setY.
protected void finalize() { try { file.close(); } catch (Exception e) { } }Производные классы
class ThreePoint extends Point { protected double z; ThreePoint() { super(); z = 0.0; } ThreePoint(double x, double y, double z) { super(x, y); this.z = z; } }Здесь мы добавили новую координату z, а поля x и y (и методы доступа к ним) унаследовали от класса Point.
class Rectangle extends Object { static final int version = 2 ; static final int revision = 0 ; }Ключевое слово final означает, что значение поля окончательное и изменению не подлежит (это константа).
abstract class Graphical extends Object { protected Point lowerLeft; protected Point upperRight; ... public void setPosition(Point ll, Point ur) { lowerLeft = ll; upperRight = ur; } abstract void drawMyself(); } class Rectangle extends Graphical { void drawMyself() { .... } }Здесь мы описали класс Graphical. В нем объявлено свойство всех графических элементов иметь какое-то положение на плоскости. Каждый элемент обязан также иметь метод для рисования самого себя, однако никакого метода рисования по-умолчанию быть не может. К Класс, содержащий хотя бы один абстрактный метод, должен быть объявлен как абстрактный. По понятным причинам создание экземпляров такого класса невозможно.
Итоги
Освещены следующие стороны Java как объектно-ориентированного языка программирования.
Нейтральность к архитектуре
Достигается прежде всего стандартизацией "бинарного формата кодов". Промежуточный код не зависит от конкретной аппаратной платформы, операционной системы и типа оконного интерфейса. Для того, чтобы программы, написанные на Java, могли работать на данной
Байт-коды
Компилятор Java производит не "машинные коды" подобно тому, как это делает, например, компилятор языка С. Вместо этого генерируются так называемые байт-коды: высокоуровневые машиннонезависимые коды для абстрактной машины, которая должна быть реализована
Сама по себе идея байт-кодов не нова, они широко используются в различных системах начиная с середины семидесятых годов. Особенности Java байт-машины следующие:
Переносимость на другие архитектуры
Кроме независимости кодов от конкретной архитектуры Java жестко специфицирует формат базовых типов данных. Без этого одна и та же программа, скомпилированная для разных аппаратных платформ, вела бы себя по-разному. Например, стандарт С/С++ не предусматри
Таким образом, решение зафиксировать форматы базовых типов данных в Java вполне естественно. Каждая Java-машина обязана реализовать их следующим образом:
byte 8-bit two's complement short 16-bit two's complement int 32-bit two's complement long 64-bit two's complement float 32-bit IEEE 754 floating point double 64-bit IEEE 754 floating point char 16-bit Unicode characterВыбор именно такого набора базовых типов и их формата обусловлен тем, что практически любой современный центральный процессор поддерживает эти форматы.
Интеллектуальность
Система Java предназначена для создания программного обеспечения, которое должно быть интеллектуальным, предельно надежным и безопасным по множеству параметров. Особое внимание уделяется как ранней диагностике возможных проблем, так и поздней, во время в
Жесткая проверка на этапе компиляции и во время выполнения
Компиляция с языка Java предусматривает жесткую проверку исходных текстов, множество ошибок может быть выявлено уже на этом этапе.
Одним из преимуществ языка С++ как строго типизованного языка является возможность раннего выявления некоторых категорий ошибок. Однако во многом этот язык наследует свойства С, позволяя нарушать требования строгого объявления функций и методов. Язык Jav
Значительное число проверок, производимых компилятором, повторяются виртуальной машиной непосредственно перед выполнением приложения. Линкер получает всю информацию о прототипах методов и на основе ее производит такую же проверку, как и компилятор, позво
Наиболее существенное отличие языка Java от С или С++ заключается в том, что архитектура Java не позволяет случайно или намеренно повредить память программы. Вместо арифметики указателей Java использует полноценные объекты для массивов и строк, что позво
Естественно, что все это не может полностью гарантировать программиста от любых ошибок, однако, Java устраняет целый класс их, существенно облегчая задачу разработчика.
Для разработчика, использующего в своей работе обычные компилируемые языки, цикл разработки обычно выглядит следующим образом: редактировать текст -- скомпилировать его -- собрать программу линкером -- загрузить -- довести ее до "падения" -- рассмотреть
Кроме того, приходится постоянно следить за тем, какие из исходных текстов подлежат перекомпиляции. Для этого обычно используются дополнительные инструменты (например, популярная утилита make), часто не связанные с конкретным языком программирования и и
Система Java в силу своей интерпретируемой и динамической природы значительно более подходит для целей быстрой разработки надежных программ.
Как уже было отмечено выше, на выходе компилятора Java мы получаем байт-коды для Виртуальной Машины Java. Полная спецификация виртуальной машины открыта и общедоступна. Она может быть реализована практически на любой из современных программно-аппаратных
Процесс сборки программы (linking) существенно ускорен по сравнению с обычными компилируемыми системами. Он представляет собой подгрузку необходимых классов и производится инкрементально, т.е. недостающие части подгружаются по мере надобности, что также
Динамическая загрузка и связывание
То, что Java является интерпретатором, позволяет расширять систему динамически. Отдельные классы загружаются лишь по мере необходимости и могут быть собраны из различных мест в сети. Перед запуском на выполнение коды проходят жесткую проверку.
В настоящее время объектно-ориентированный подход стал общепринятым. В качестве языка программирования при этом обычно выбирают С++. Однако этот язык обладает определенным недостатком, который известен под названием "проблемы хрупкости базового класса" (
"Проблема хрупкости базового класса" в С++
Эта проблема возникает как побочный эффект реализации модели С++. Каждый раз, когда Вы добавляете новый метод или переменную в класс, все остальные модули приложения, использующие этот класс, требуют перекомпиляции. В противном случае программа успешно с
Решение "проблемы хрупкости базового класса"
В системе программирования Java эта проблема решается в несколько этапов. Во-первых, компилятор не разрешает ссылок вплоть до численных значений. Напротив, символьная информация передается вместе с байт-кодами для проверки и интерпретации. Окончательное
Во вторых то, как объект должен выглядеть в памяти машины, определяется не компилятором, а самим интерпретатором. Добавление в класс новых переменных или методов не требует изменений в остальных кодах.
Понятие интерфейса в языке Java
Под интерфейсом (interface) в Java понимается спецификация дополнительного набора методов, которые "обязан знать" объект. Идея заимствована из языка Objective C, где такая спецификация называется протоколом (protocol). Интерфейс не включает в себя модифи
Представление в исполняемом модуле
Классы в Java реально представлены в работающей системе. Существует выделенный класс по имени Class, экземпляры которого создаются виртуальной машиной и содержат информацию о всех классах в системе. Для любого объекта возможно найти соответствующий ему о
Итоги
Интерпретируемая и динамическая природа языка Java предоставляет разработчику определенные преимущества:
По мере стремительного роста использования глобальных сетей в спектре услуг, простирающемся от электронного распространения программного обеспечения и объектов multimedia до электронных платежей, безопасность становится ключевой проблемой. Мы коснемся то
Компилятор и run-time включают в себя несколько уровней обороны против потенциально опасных программ. В общем случае система исходит из предположения, что доверять нельзя никому. Следующие несколько секций касаются проблемы более детально.
Резервирование и распределение памяти
Во-первых, решение о распределении памяти принимает не компилятор, а run-time система. Оно может зависеть от особенностей архитектуры конкретной системы.
Во-вторых, язык не поддерживает указателей. Символические ссылки на объекты разрешаются интерпретатором на этапе выполнения. Выделение памяти и работа со ссылками находятся полностью под управлением системы и не доступны непосредственно из программы.
Отложенное до последнего момента размещение структур в памяти не позволяет определить реальное положение полей класса по его описанию.
Процесс проверки байт-кодов
Несмотря на то, что компилятор гарантирует, что коды не нарушают требований безопасности, если они были получены из других точек сети возникает следующая проблема: коды могут быть созданы не компилятором Java, а другими средствами. Или они могут быть нам
Проверка включает в себя несколько этапов, начиная с контроля целостности формата полученного файла до анализа каждого фрагмента кодов на предмет выполнения следующих правил:
Правила безопасности при загрузке
В ходе выполнения программы может потребоваться загрузка дополнительных классов. После того как, полученный код прошел проверку на валидность байт-кодов, он поступает в загрузчик кодов. Для загрузчика все пространство имен загружаемых классов может быть
При разрешении ссылки на какой-либо класс он ищется прежде всего в локальном пространстве. Это не позволяет "внешним" кодам подменить один из базовых классов в системе.
Безопасность в сетевом пакете
Сетевой пакет Java включает в себя поддержку различных сетевых протоколов (FTP, HTTP, Telnet и т.д.). Это -- передовая линия защиты от вторжения по сети.
Осторожность при установке прав сетевого доступа в локальную систему может быть доведена до параноидальной. Вы можете
Итоги
Система Java достаточно безопасна, чтобы жить в сетевом окружении. Нейтральность к архитектуре и переносимость делают ее достаточно привлекательной для создания распределенных по сети приложений.
Современного пользователя компьютера все чаще раздражает ситуация, когда программа способна выполнять в один момент времени лишь одну задачу. Реальный мир наполнен событиями, происходящими одновременно и независимо. Пользователь требует от компьютера аде
К сожалению, написание программ, отвечающих этим требованиям, значительно сложнее, чем написание программ, выполняющихся последовательно. Они могут быть созданы с использованием С или С++, однако делать это сложнее, т.к. отсутствует поддержка в самом язы
Термин thread-safe означает, что каждая функция данной библиотеки может быть использована одновременно несколькими потоками.
Основная проблема при прямом управлении потоками состоит в том, что Вы никогда не можете быть полностью уверены, что поставили все нужные замки (locks) и вовремя их освободили. При преждевременном завершении процедуры или при возникновении исключительной
Встроенная многопотоковость -- существенная черта архитектуры Java. Стандартная библиотека включает в себя класс Thread, с методами, позволяющими стартовать новый поток, завершить его работу и проверить текущее состояние потока.
Интеграция примитивов синхронизации непосредственно в язык упрощает работу с ними.
Потоки в Java вытесняющие (pre-emptive), а также могут выполняться в режиме разделения времени (time-sliced), но только на платформах, которые поддерживают это. В системах, в которых такая поддержка отсутствует, после того, как поток был запущен, он може
Интегрированная синхронизация потоков
Система Java содержит поддержку многопотоковости как на уровне синтаксиса языка, так и на уровне библиотек и системных вызовов.
На уровне самого языка методы, объявленные с признаком synchronized, гарантировано не будут выполняться одновременно для данного объекта. Методы запускаются под управлением монитора (monitor). Каждый класс и объект имеют свой собственный монитор. Если об