Язык и архитектура JavaВведение Преамбула На сегодняшний день создание программного обеспечения представляет
собой чрезвычайно тяжелое занятие. Трудности связаны с разнообразием архитектур
машин, операционных систем, графических оболочек и т.д.. Кроме того, ваши приложения
должны работать в распределенных системах. Стремительный рост технологий, связанных
с Интернетом, WWW и "электронной коммерцией", дополнительно усложняют эту задачу.
Модный ныне объектно-ориентированный подход сам по себе не решает этих проблем,
более того, часто привносит новые. язык программирования объектно-ориентирован, в то же время довольно прост для освоения цикл разработки приложений сокращен за счет того, что система построена на основе интерпретатора приложение получается автоматически переносимым между множеством платформ и операционных систем за счет встроенной системы сборки мусора программист освобождается от необходимости явного управления памятью в интерактивном графическом приложении удается достичь высокой производительности (быстрого отклика на ввод пользователя) за счет встроенной в систему многопотоковости приложение легко сопровождается и модифицируется, т.к. модули могут быть загружены с сети в приложения встроена система безопасности, не допускающая незаконного доступа и проникновения вирусов Основы проекта Java. Немного истории Целью проекта было создание небольшой, надежной, переносимой
и распределенной системы реального времени. Исходно в качестве языка планировалось
использование языка программирования С++, но постепенно связанные с ним трудности
привели к необходимости создания нового языка. Система должна была вобрать в
себя лучшие черты из множества современных систем программирования -- Eiffel,
Smalltalk, Objective C, Cedar/Mesa и т. д.. проста, поэтому может быть использована широким кругом разработчиков объектно ориентирована, что соответствует современному взгляду на программирование поддерживает многопотоковость, что позволяет выполнять несколько задач одновременно интерпретируема, что обеспечивает переносимость и улучшает динамические свойства Чтобы не быть голословным, рассмотрим каждое из этих свойств по отдельности.Свойства Java, краткий обзор Java проста, объектно ориентированна и знакома анализ кодов на соблюдение правил безопасности производится один раз до запуска кодов на выполнение, в момент выполнения таких проверок уже не нужно, и коды выполняются максимально эффективно работа с базовыми типами максимально эффективна, для операций с ними зарезервированы специальные байт-коды методы в классах не обязательно связываются динамически автоматический сборщик мусора работает отдельным фоновым потоком, не замедляя основную работу программы, но в то же время обеспечивая своевременный возврат свободной памяти в систему стандарт предусматривает возможность написания критических по производительности участков программы в машинных кодах Интерпретируемый, многопотоковый и динамическийИнтерпретируемая природа языка позволяет сделать фазу линкования простой, инкрементальной и, следовательно, быстрой. Это резко сокращает цикл разработки и тестирования программных фрагментов. Многопотоковость позволяет выполнять в рамках одного приложения несколько задач одновременно. Это становится особенно актуально в современных распределенных приложениях, когда процессы сетевого обмена могут идти одновременно и асинхронно. При этом программа продолжает реагировать на ввод информации пользователем без неприятных задержек. Многопотоковость поддерживается на уровне языка -- часть примитивов синхронизации встроена в систему реального времени, а библиотека содержит базовый класс Thread. К тому же системные библиотеки написаны thread-safe, т.е. все они могут быть использованы в многопотоковых приложениях. Система обеспечивает динамическую сборку программы. Классы подгружаются по мере необходимости, причем загружены они могут быть с любой точки сети, что позволяет сделать внесение изменений в приложения прозрачным для пользователя. Пользователь может быть уверен, что всегда работает со свежей версией приложения. Базовая система Java Опыт показывает, что отсутствие стандартных базовых библиотек
для языка С++ чрезвычайно затрудняет работу с ним. В силу того, что любое нетривиальное
приложение требует наличия некоторого набора базовых классов, разработчикам
приходится пользоваться различными несовместимыми между собой библиотеками или
писать свой собственный вариант такого набора. Все это затрудняет как разработку,
так и дальнейшую поддержку приложений, затрудняет стыковку приложений, написанных
разными людьми. java.lang -- базовый набор типов, отраженных в самом языке. Этот пакет обязательно входит в состав любого приложения. Содержит описания классов Object и Class, а также поддержку многопотоковости, исключительных ситуаций, оболочку для базовых типов, а также некоторые фундаментальные классы. java.io -- потоки и файлы произвольного доступа. Аналог библиотеки стандартного ввода-вывода системы UNIX. Поддержка сетевого доступа (sockets, telnet, URL) содержится в пакете java.net. java.util -- классы-контейнеры (Dictionary, HashTable, Stack) и некоторые другие утилиты. Кодирование и декодирование. Классы Date и Time. java.awt -- Abstract Windowing Toolkit, архитектурно-независимый оконный интерфейс, позволяющий запускать интерактивные оконные Java-приложения на любой платформе. Содержит базовые компоненты интерфейса, такие как события, цвета, фонты, а также основные оконные элементы -- кнопки, scrollbars и т.д.. Результат -- новый подход к распределенным вычислениям Каждая из перечисленных характеристик по отдельности может
быть найдена в уже существующих программных пакетах. Новым является соединение
их в стройную непротиворечивую систему, которая должна стать всеобщим стандартом.
На сегодняшний день наиболее популярными языками программирования
являются С и С++. Из них двоих лишь С++ претендует на объектную ориентацию.
Характеристики этого языка складывались в ходе длинной истории его развития,
причем довольно хаотично, каждое новое свойство не отменяло всех предыдущих.
Стандарт языка до сих пор не зафиксирован, т.к. новые свойства продолжают появляться
по сей день. В результате С++ стал бесконечно сложным и избыточным -- одну и
ту же операцию возможно реализовать на языке множеством способов. делают невозможным контроль безопасности приложений не являются абсолютно необходимыми, чаще мешают программисту, чем облегчают его задачу являются источником наиболее трудно и поздно распознаваемых ошибок В то же время в языке Java полностью сохранен "дух" программирования на С++, опытным С++ программистам потребуется одна-две недели на освоение самого языка, а огромный объем программного обеспечения, уже созданного с использованием С++, может быть адаптирован под новый язык относительно легко.Основные свойства языка программирования Java Встроенные (примитивные) типы данных целые числа: 8-бит byte, 16-бит short, 32-бит int, 64-бит long. Все числа со знаком, ключ unsigned из языка удален. числа с плавающей точкой. 32-бит float, 64-бит double. Представление должно соответствовать стандарту IEEE 754. CharacterОтличаются от С++ как синтаксисом, так и представлением. Тип character есть 16-разрядное число без знака (диапазон 0-65,535). Кодировка соответствует стандарту Unicode. В силу того, что эта кодировка в идеале должна охватывать все существующие в мире языки, это представление должно облегчить локализацию приложений. Boolean Этот тип данных не выделен в С++, однако неявно присутствует практически во всех программах. В Java тип называется boolean, может принимать значения true и false и не может (в отличие от С++) быть преобразован в другой тип. Операторы Добавлен новый оператор >>> логического сдвига вправо (т.к. нет беззнаковых целых чисел). Встроенная операция слияния строк (оператор +). Массивы В отличие от С++ массивы в Java являются полноценными объектами с определенным runtime представлением. Декларация: Point myPoints[];резервирует ссылку на массив, а не место под реальный объект. Сам массив может быть затем создан выполнением myPoints = new Point[10];а его элементы заполнены операцией типа: myPoints[2] = new Point();Размер массива может быть получен во время выполнения программы: howMany = myPoints.length;Значение индекса проверяется при каждом обращении, при ошибке возбуждается исключительная ситуация. Указатели полностью исключены из языка вместе с целой категорией трудноуловимых ошибок "замедленного действия". К тому же наличие указателей противоречит требованиям безопасности и усложняет реализацию сборщика мусора. Strings Строки в Java являются полноценными объектами. Они делятся на текстовые константы (Strings) и модифицируемые строки (StringBuffer). Компилятор позволяет явно определять текстовые литералы в программе подобно тому, как это делается в С++ String hello = "Hello world!";Ссылка hello инициируется объектом класса String на основе представления "Hello world!" в кодировке Unicode. Оператор "+" может быть применен к строкам, например System.out.println("There are" + num + "characters in the file.");Multi-Level Break В Java отсутствует выражение goto. Анализ С/С++ текстов показал, что подавляющее число случаев использования этого оператора связано с необходимостью выхода из вложенного цикла. Для отработки таких ситуаций в Java перед началом блока может ставиться метка, а инструкции break и continue также могут сопровождаться меткой, на которую должен быть осуществлен переход. Например: test: for(int i = 0; i < 10; i++) for(int j = 0; j < 10; j++) if( i > 3) break test;Управление памятью, сборка мусора Необходимость явно управлять памятью в С/С++ программах всегда была большой занозой для программистов. Мало того, что сами программы изобиловали вызовами функции free или операторами delete, непосредственно к логике программы отношения не имеющими. Ошибки, связанные с неосвобождением памяти или наоборот, с удалением уже однажды удаленных объектов, относятся к категории ошибок наиболее трудных для обнаружения и исправления. Java полностью снимает эту заботу с программиста. Автоматический сборщик мусора обязан быть встроен в run-time системы. Память объектов, на которые больше нет ссылок, в конце концов возвращается в систему. Опыт показывает, что несмотря на относительную сложность сборщиков мусора, производительность системы в целом может оказаться не меньше, а часто и больше, чем при явном освобождении памяти программой. Сборка мусора в фоновом режиме Одно из преимуществ того, что Java-приложения многопотоковые, заключается в том, что сборка мусора может производиться в фоновом потоке. Этот поток имеет меньший приоритет выполнения, чем остальные, поэтому система всегда готова ответить на действия пользователя, отсутствуют "периоды молчания", в которые производится только сборка мусора. С другой стороны, паузы в операциях пользователя сборщик мусора может использовать для своей работы, обеспечивая наличие свободной памяти в моменты, когда это необходимо. Встроенная синхронизация потоков Java поддерживает многопотоковость не только на уровне библиотек, но и на уровне самого языка, что значительно облегчает построение приложений, надежно работающих в многопотоковом режиме. Свойства, присутствующие в С и С++, и удаленные из Java Конструкция typedef, препроцессор int myInt; double myFloat = 3.14159; myInt = myFloat; // допустимо в С++, недопустимо в Java myInt = (int)myFloat; // допустимо в JavaИсключение составляет преобразование между встроенными численными типами без потери информации. Указатели Большинство исследований показали, что применение указателей в С/С++ являются одним из основных источников ошибок. В силу того, что в языке больше не стало структур, а массивы и строки превратились в полноценные объекты, надобность в указателях отпала. Содержимое строк и массивов доступно только по индексам, причем контроль доступа во время выполнения не позволяет выходить за границы массива или строки. Итоги Итак, мы показали два из основных свойства языка программирования
Java знакомый -- Java сохраняет стиль программирования C и С++ простой -- количество конструкций языка в Java существенно сокращено по сравнению с С и С++
Система Java создавалась объектно ориентированной с самого
начала. Объектно-ориентированная парадигма наиболее удобна при создании программного
обеспечения типа клиент-сервер, а также для организации распределенных вычислений. Основные требования к объектно-ориентированной системе
инкапсуляция -- сокрытие реализации за абстрактным интерфейсом полиморфизм -- одно и то же сообщение, посланное различным объектам, приводит к выполнению разных операций наследование -- новые классы могут наследовать данные и функциональность уже существующих классов динамическое связывание -- новые классы могут появляться в системе откуда угодно, в том числе и из сети. Необходимо иметь возможность динамически включать их в систему Объектная модель 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. Финализаторы Специальное имя finalize зарезервировано для метода, который будет вызван сборщиком мусора перед тем, как объект будет уничтожен. В силу того, что Java освобождает нас от необходимости самим следить за освобождением памяти, занимаемой объектами, необходимость в таких методах обычно возникает лишь тогда, когда надо освободить какие-то внешние ресурсы, например, закрыть открытый файл: 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. Контроль доступа Контроль доступа к данным и методам объекта в Java несколько отличается от С++. Помимо трех уровней доступа, имеющихся в С++ (public, private, protected) имеется четвертый, находящийся где-то между уровнями public и protected. Он не имеет имени и используется по умолчанию, когда явно не указан другой уровень. Поля этого типа доступны внутри только одного программного пакета. Пакет представляет группу классов, объединенных в одну логическую группу. Например, классы, описывающие точку и прямоугольник в графическом пакете, могут иметь прямой доступ к полям данных друг друга, запрещенный обычно для остального мира. Также следует отметить, что контроль доступа в C++ помогает программисту лишь при построении программы. Различия между полями, помеченными public и private, отсутствуют в выполняемом модуле, созданном с использованием этого языка. В Java контроль доступа реален, т.к. он осуществляется не только при компиляции, но и непосредственно перед запуском кодов на выполнение виртуальной машиной. Переменные и методы класса Как и С++ язык Java позволяет использовать переменные и методы, принадлежащие классу целиком. Для определения их используется ключевое слово static. Естественно, что методы самого класса не могут оперировать данными и методами объекта класса, т.к. они не относятся ни к какому определенному объекту. Например, версия реализации класса Rectangle может быть задана следующим образом: 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. В нем объявлено свойство всех графических элементов иметь какое-то положение на плоскости. Каждый элемент обязан также иметь метод для рисования самого себя, однако никакого метода рисования по-умолчанию быть не может. Класс Rectangle, представляющий собой конкретную реализацию для типа Graphical, реализует также этот метода для объекта прямоугольной формы. Класс, содержащий хотя бы один абстрактный метод, должен быть объявлен как абстрактный. По понятным причинам создание экземпляров такого класса невозможно. Итоги Освещены следующие стороны Java как объектно-ориентированного
языка программирования. Классы определяют шаблон, по которому создаются конкретные объекты Поля данных объекта определяют состояние объекта Объекты обмениваются сообщениями между собой. Получение сообщения приводит к вызову одного из методов Методы определяют поведение объекта данного класса. Методы для разных классов могут иметь одно и то же имя, но различное содержание.
Нейтральность к архитектуре Достигается прежде всего стандартизацией "бинарного формата
кодов". Промежуточный код не зависит от конкретной аппаратной платформы, операционной
системы и типа оконного интерфейса. Для того, чтобы программы, написанные
на Java, могли работать на данной аппаратно-программной платформе, достаточно,
чтобы для нее была создана лишь соответствующая виртуальная машина. набор ее кодов легко не только интерпретировать, но и эффективно скомпилировать "на лету" непосредственно в машинные коды для любой современной аппаратной платформы коды содержат избыточную информацию, которая позволяет проверить их на безопасность выполнения Переносимость на другие архитектуры Кроме независимости кодов от конкретной архитектуры Java
жестко специфицирует формат базовых типов данных. Без этого одна и та же программа,
скомпилированная для разных аппаратных платформ, вела бы себя по-разному.
Например, стандарт С/С++ не предусматривает конкретного представления для
целого типа int. Предполагается, что этому типу соответствует основной формат
машинного слова для данной архитектуры. В результате программа, написанная
для 32-разрядного процессора, чаще всего переносится на 16-разрядную архитектуру
с очень большими усилиями. 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 сам написан на этом языке. Виртуальная машина написана на ANSI C в соответствии со стандартом POSIX. Спецификация языка не содержит ссылок типа "в зависимости от конкретной реализации". Интеллектуальность Система Java предназначена для создания программного обеспечения,
которое должно быть интеллектуальным, предельно надежным и безопасным по множеству
параметров. Особое внимание уделяется как ранней диагностике возможных проблем,
так и поздней, во время выполнения кодов.
Для разработчика, использующего в своей работе обычные компилируемые
языки, цикл разработки обычно выглядит следующим образом: редактировать текст
-- скомпилировать его -- собрать программу линкером -- загрузить -- довести
ее до "падения" -- рассмотреть обломки -- начать все с начала. Динамическая загрузка и связывание То, что Java является интерпретатором, позволяет расширять
систему динамически. Отдельные классы загружаются лишь по мере необходимости
и могут быть собраны из различных мест в сети. Перед запуском на выполнение
коды проходят жесткую проверку. Итоги Интерпретируемая и динамическая природа языка Java предоставляет
разработчику определенные преимущества: интерпретирующее окружение позволяет быстрое создание прототипов без обычного цикла перекомпиляции и сборки среда динамически расширяема, т.к. классы подгружаются на лету по мере необходимости характерная для С++ проблема "хрупкого базового класса" решена в силу того, что расположение элементов объекта в памяти определяется не на этапе компиляции, а на этапе выполнения
По мере стремительного роста использования глобальных сетей
в спектре услуг, простирающемся от электронного распространения программного
обеспечения и объектов multimedia до электронных платежей, безопасность становится
ключевой проблемой. Мы коснемся того, как компилятор Java и run-time предотвращают
создание и проникновение "диверсионных" кодов.
Во-первых, решение о распределении памяти принимает не компилятор,
а run-time система. Оно может зависеть от особенностей архитектуры конкретной
системы. Процесс проверки байт-кодов Несмотря на то, что компилятор гарантирует, что коды не нарушают
требований безопасности, если они были получены из других точек сети возникает
следующая проблема: коды могут быть созданы не компилятором Java, а другими
средствами. Или они могут быть намеренно модифицированы после создания. Поэтому
run-time система подвергает полученные коды тщательной проверке. нет незаконных манипуляций с указателями нет попыток нарушения прав доступа объекты используются в строгом соответствии с их типами, например, объекты класса InputStream используются только как InputStream и никак иначе. Верификатор байт-кодовВерификатор байт-кодов (bytecode verifier) сканирует байт-коды, извлекает информацию о типах объектов в каждой точке выполнения фрагмента кода. На приведенном рисунке изображен путь от исходных текстов на языке Java через компилятор Java, верификатор кодов до интерпретатора. Важно отметить, что загрузчик и верификатор байт-кодов не делают никаких предположений относительно происхождения кодов -- получены они с локальной файловой системы или с другого континента. Верификатор гарантирует, что любой код, прошедший проверку, может быть использован интерпретатором без риска повредить его (интерпретатор), а именно: не может произойти переполнение или "исчерпание" стека параметры для инструкций байт-машины имеют нужный тип доступ к полям и методам объектов не нарушает объявленных в классе правил (public, private, protected) Правила безопасности при загрузке В ходе выполнения программы может потребоваться загрузка
дополнительных классов. После того как, полученный код прошел проверку на
валидность байт-кодов, он поступает в загрузчик кодов. Для загрузчика все
пространство имен загружаемых классов может быть подразделено на отдельные
области (name spaces). Причем классы, полученные локально (заслуживающие безусловного
доверия), и классы, присланные по сети из остального мира (и потенциально
враждебные), находятся в разных пространствах имен. Безопасность в сетевом пакете Сетевой пакет Java включает в себя поддержку различных сетевых
протоколов (FTP, HTTP, Telnet и т.д.). Это -- передовая линия защиты от вторжения
по сети. запретить сетевой доступ вообще разрешить доступ только к тому узлу, с которого был получен код разрешить доступ только к узлам за пределами firewall, если код также получен с той стороны firewall разрешить любой сетевой доступ Итоги Система Java достаточно безопасна, чтобы жить в сетевом окружении.
Нейтральность к архитектуре и переносимость делают ее достаточно привлекательной
для создания распределенных по сети приложений.
Современного пользователя компьютера все чаще раздражает
ситуация, когда программа способна выполнять в один момент времени лишь одну
задачу. Реальный мир наполнен событиями, происходящими одновременно и независимо.
Пользователь требует от компьютера адекватной реакции.
Система Java содержит поддержку многопотоковости как на уровне
синтаксиса языка, так и на уровне библиотек и системных вызовов. Поделитесь этой записью или добавьте в закладки | Полезные публикации |