ВВЕДЕНИЕ. 3
1. ИНТЕРНЕТ, WWW И ИНТРАНЕТ. 6
2. JAVA, JOE, NEO. 11
3. JAVA - ЯЗЫК И ТЕХНОЛОГИЯ. 14
Мобильность Java. 14
ОБЪЕКТНАЯ МОДЕЛЬ ЯЗЫКА JAVA. 16
КЛАССЫ. 16
НАСЛЕДОВАНИЕ. Интерфейсы. 21
ЖИЗНЕННЫЙ ЦИКЛ ОБЪЕКТА. 23
Базовые типы данных. 23
Массивы в Java. 25
ПАКЕТЫ. 27
УПРАВЛЯЮЩИЕ КОНСТРУКЦИИ. 28
ИСКЛЮЧИТЕЛЬНЫЕ СИТУАЦИИ. 28
МЕХАНИЗМ ПОТОКОВ. 31
КЛАСС THREAD И ИНТЕРФЕЙС RUNNABLE 31
СРЕДСТВА СИНХРОНИЗАЦИИ ПОТОКОВ 33
Библиотеки классов Java 37
Встроенные классы. 37
Замещающие классы. 37
Класс String. 38
Другие встроенные классы. 38
Подключаемые библиотеки классов. 39
Библиотека классов java.util. 39
Библиотека классов java.io. 39
Библиотека классов java.net. 39
Библиотека классов java.awt. 40
Библиотека классов java.awt.image. 40
Библиотека классов java.awt.peer. 40
Библиотека классов java.applet. 41
ТЕХНОЛОГИЯ JAVA. 41
ТЕХНОЛОГИЧЕСКИЙ ЦИКЛ ОБРАБОТКИ JAVA-ПРОГРАММ. 41
JAVA-МАШИНА. 43
ТИПЫ ДАННЫХ, ПОДДЕРЖИВАЕМЫЕ JAVA-МАШИНОЙ. 44
РЕГИСТРЫ. 45
Указатели, которых нет. 46
СБОР МУСОРА. 47
СИСТЕМА КОМАНД JAVA-МАШИНЫ. 47
4. СВЯЗЬ JAVA С ОКРУЖЕНИЕМ: ОКОННЫЙ ИНСТРУМЕНТАРИЙ. 49
ОБЩИЕ ПОЛОЖЕНИЯ. 49
ИЗ ЧЕГО СТРОИТСЯ ГРАФИЧЕСКИЙ ИНТЕРФЕЙС (КОМПОНЕНТЫ И КОНТЕЙНЕРЫ). 50
5. JAVA И БЕЗОПАСНОСТЬ. 52
Вывод. 54
ВВЕДЕНИЕ.
Казалось бы, на сегодняшний день изобретены уже все языки программирования, какие только можно придумать. Но нет - появился еще один, с названием Java. Этот язык сумел получить весьма заметную известность за последние несколько лет, так как он ориентирован на самую популярную компьютерную среду - сеть Internet и серверы Web.
Персональные компьютеры сделали информационные технологии частью массовой культуры. И тем не менее, уже довольно длительная история развития персональных компьютеров не знала ничего, подобного феномену Java. Что изменилось в мире в последние годы, почему этот феномен стал возможен?
Изменился Интернет. Он стал доступен миллионам людей, далеких от технических проблем. Число пользователей Интернет по порядку величины уже не отличается от числа пользователей персональных компьютеров и продолжает взрывообразно расти. Одновременно Интернет обеспечил такую скорость распространения новинок информационных технологий, которую не могли и никогда не смогут дать традиционные каналы сбыта. Время спрессовалось. В Интернет, опоздав буквально на день, компьютерная компания, даже крупная, рискует серьезно ослабить свои позиции сразу во всем мире.
Язык Java произошел от языка программирования Oak (а не от C++, как думают многие). Oak был приспособлен для работы в Internet и затем переименован в Java.
Синтаксис Java близок к синтаксису языка C++. Унаследовав самое лучшее от языка программирования C++, язык Java при этом избавился от некоторых недостатков C++, в результате чего на нем стало проще программировать. В этом языке нет, например, указателей, которые сложны в использовании и потенциально могут послужить причиной доступа программы к не принадлежащей ей области памяти. Нет множественного наследования и шаблонов, хотя функциональные возможности языка Java от этого не пострадали.
Огромное преимущество Java заключается в том, что на этом языке можно создавать приложения, способные работать на различных платформах. К сети Internet подключены компьютеры самых разных типов - Pentium PC, Macintosh, рабочие станции Sun и так далее. Даже в рамках компьютеров, созданных на базе процессоров Intel, существует несколько платформ, например, Microsoft Windows версии 3.1, Windows 95, Windows NT, OS/2, Solaris, различные разновидности операционной системы UNIX с графической оболочкой XWindows. Между тем, создавая сервер Web в сети Internet, хотелось бы, чтобы им могло пользоваться как можно большее число людей. В этом случае выручают приложения Java, предназначенные для работы на различных платформах и не зависящие от конкретного типа процессора и операционной системы.
Программы, составленные на языке программирования Java, можно разделить по своему назначению на две большие группы.
К первой группе относятся приложения Java, предназначенные для автономной работы под управлением специальной интерпретирующей машины Java. Реализации этой машины созданы для всех основных компьютерных платформ.
Вторая группа - это так называемые аплеты (applets). Аплеты представляют собой разновидность приложений Java, которые интерпретируются виртуальной машиной Java, встроенной практически во все современные браузеры.
Приложения, относящиеся к первой группе (будем называть их просто приложениями Java), - это обычные автономные программы. Так как они не содержат машинного кода и работают под управлением специального интерпретатора, их производительность заметно ниже, чем у обычных программ, составленных, например, на языке программирования C++. Однако не следует забывать, что программы Java без перетрансляции способны работать на любой платформе, что само по себе имеет большое значение в плане разработок для Internet.
Аплеты Java встраиваются в документы HTML, хранящиеся на сервере Web. С помощью аплетов можно сделать страницы сервера Web динамичными и интерактивными. Аплеты позволяют выполнять сложную локальную обработку данных, полученных от сервера Web или введенных пользователем с клавиатуры. Из соображений безопасности аплеты (в отличие от обычных приложений Java) не имеют никакого доступа к файловой системе локального компьютера. Все данные для обработки они могут получить только от сервера Web. Более сложную обработку данных можно выполнять, организовав взаимодействие между аплетами и расширениями сервера Web - приложениями CGI и ISAPI.
Для повышения производительности приложений Java в современных браузерах используется компиляция "на лету"- Just-In-Time compilation (JIT). При первой загрузке аплета его код транслируется в обычную исполнимую программу, которая сохраняется на диске и запускается. В результате общая скорость выполнения аплета Java увеличивается в несколько раз.
Язык Java является объектно-ориентированным и поставляется с достаточно объемной библиотекой классов. Так же как и библиотеки классов систем разработки приложений на языке C++, библиотеки классов Java значительно упрощают разработку приложений, представляя в распоряжение программиста мощные средства решения распространенных задач. Поэтому программист может больше внимания уделить решению прикладных задач, а не таких, как, например, организация динамических массивов, взаимодействие с операционной системой или реализация элементов пользовательского интерфейса.
ИНТЕРНЕТ, WWW И ИНТРАНЕТ.
Информационные перегрузки - характерная черта нашего времени. Созданы мощные механизмы, обеспечивающие производство огромного количества информации. Существенно меньше сделано для облегчения ее получения и усвоения.
Типичной является ситуация, когда инициатива принадлежит поставщику, а не потребителю информации. Поставщик по определенному поводу создает информацию и направляет ее всем, кто, по его мнению, в ней нуждается.
Риc.1. Доставка информации по инициативе поставщика.
Так работают средства массовой информации, издательства, рекламные агентства. Как работает электронная почта. В большинстве случаев потребителю эта информация, может быть, и нужна, но не в данный момент, не сейчас. Потребитель вынужден архивировать полученную информацию. При этом в лучшем случае велика вероятность, что к моменту, когда информация действительно понадобится, она потеряет актуальность. Обычно же у потребителя просто накапливаются горы мусора, в котором отыскать нечто нужное почти невозможно.
Чтобы информация была актуальной для потребителя, она должна доставляться к нему по запросу - в точности тогда, когда в ней возникла необходимость. Кроме того, поставщик должен сохранять возможность управления информацией, он должен не только создавать ее, но и вовремя обновлять и уничтожать.
Централизованные компьютерные системы, доминировавшие еще 10 лет назад, позволяли пользователям сравнительно легко находить информацию в оперативном режиме, однако они затрудняли управление информацией, поскольку ее источники,
Риc. 2. Взаимодействие с централизованной компьютерной системой.
как правило, разнородны и территориально разнесены.
Еще один важный недостаток централизованных систем - их сложность и дороговизна. Сети персональных компьютеров существенно дешевле централизованных систем, они оставляют за поставщиком необходимую свободу управления информацией, однако потребителям приходится искать необходимые данные на множестве машин, среди большого числа приложений с различными интерфейсами. Рядовому пользователю работать в такой разнородной прикладной среде крайне неудобно.
Рис.3. Получение информации из сети персональных компьютеров
.
Способ разрешения указанных проблем, к которому прибегают ведущие компании, состоит в построении информационной структуры организации по образу и подобию Интернет, с Web-сервисом в качестве концептуальной основы.
Риc.4. Универсальный клиент Web-сервиса.
В
Возможность хранения данных различных типов (текст, графика, аудио, видео) в сочетании с механизмами связывания информации, расположенной в разных узлах компьютерной сети, позволяют рассредоточивать информацию в соответствии с естественным порядком ее создания и потребления, осуществлять единообразный доступ, отправляясь от небольшого числа известных "корней". Тем самым поставщик может эффективно готовить и контролировать информацию, а потребитель в состоянии без труда найти необходимые данные именно тогда, когда они стали нужны.
Средства Web, помимо связывания распределенных данных, осуществляют еще одну очень важную функцию. Они позволяют рассматривать информацию с нужной степенью детализации, что существенно упрощает анализ больших объемов данных. Можно быстро отобрать самое интересное, а затем изучить выбранный материал во всех подробностях.
Таким образом, Web-серверы и Web-навигаторы могут и должны использоваться не только в "мировом масштабе". Web - это инфраструктурный сервис, необходимый каждой организации со сколько-нибудь заметными информационными потоками.
В то же время, Web-сервису присущи и определенные недостатки, вытекающие из отсутствия объектной ориентации и из природы HTTP-протокола. Во-первых, клиент по существу лишен средств управления внешним представлением объектов на просматриваемой WWW-странице.
Во-вторых, Web-страницы статичны. При использовании протокола HTTP, на клиентскую систему передаются только пассивные данные, но не методы объектов. Из общих соображений очевидна ограниченность подобного подхода. Данный недостаток, разумеется, связан с первым. Объект сам должен знать, как себя показывать - точнее говоря, он должен это выяснить, проанализировав клиентское окружение.
В-третьих, Web-сервис обладает весьма ограниченными интерактивными возможностями, которые сводятся к заполнению пользователем чисто текстовых форм с последующей отправкой на сервер. Сервер анализирует полученные данные, после чего формирует и возвращает клиенту новую WWW-страницу, которая нередко вновь оказывается формой. Такой стиль общения не всегда устраивает пользователей.
Java-технология позволяет устранить все отмеченные недостатки. Как именно - будет ясно из последующего изложения. В результате Web-сервис, и без того имевший огромную популярность, получил как бы новый импульс. Этот экспресс понесся вперед с удвоенной скоростью, увлекая за собой и Java.
JAVA, JOE, NEO.
В узком смысле слова Java - это объектно-ориентированный язык, напоминающий C++, но более простой для освоения и использования. В более широком смысле Java - это целая технология программирования, изначально рассчитанная на интеграцию с Web-сервисом, то есть на использование в сетевой среде, Поскольку Web-навигаторы существуют практически для всех аппаратно-программных платформ, Java-среда должна быть как можно более мобильной, в идеале полностью независимой от платформы.
С целью решения перечисленных проблем были приняты, помимо интеграции с Web-навигатором, два других важнейших постулата:
Была специфицирована виртуальная Java-машина, на которой должны выполняться (интерпретироваться) Java-программы. Определены ее архитектура, представление элементов данных и система команд. Исходные Java-тексты транслируются в коды этой машины. Тем самым, при появлении новой аппаратно-программной платформы в портировании будет нуждаться только Java-машина; все программы, написанные на Java, пойдут без изменений.
Определено, что при редактировании внешних связей Java-программы и при работе Web-навигатора прозрачным для пользователя образом может осуществляться поиск необходимых объектов не только на локальной машине, но и на других компьютерах, доступных по сети (в частности, на WWW-сервере). Найденные объекты загружаются, а их методы выполняются затем на машине пользователя.
Несомненно, между двумя сформулированными положениями существует тесная связь. В компилируемой среде трудно как дистанцироваться от аппаратных особенностей компьютера, так и реализовать прозрачную динамическую загрузку по сети. С другой стороны, прием объектов извне требует повышенной осторожности при работе с ними, а, значит, и со всеми Java-программами. Принимать необходимые меры безопасности проще всего в интерпретируемой среде. Вообще, мобильность, динамизм и безопасность - спутники интерпретатора, а не компилятора.
Принятые решения сделали Java-среду идеальным средством разработки клиентских компонентов Web-систем. Особо отметим прозрачную для пользователя динамическую загрузку объектов по сети. Из этого вытекает такое важнейшее достоинство, как нулевая стоимость администрирования клиентских систем, написанных на Java. Достаточно обновить версию объекта на сервере, после чего клиент автоматически получит именно ее, а не старый вариант. Без этого реальная работа с развитой сетевой инфраструктурой практически невозможна. С другой стороны, при наличии динамической загрузки действительно возможно появление устройств класса Java-терминалов, изначально содержащих только WWW-навигатор, а все остальное (и программы, и данные) получающих по сети.
Здесь уместно отметить замечательную точность в выборе основных посылок проекта Java. Из минимума предположений вытекает максимум новых возможностей при сохранении практичности реализации.
В то же время, интеграция с WWW-навигатором и интерпретируемая природа Java-среды ставят вполне определенные рамки для реального использования Java-программ (хотя, конечно же, язык Java не менее универсален, чем, скажем, C++). Например, известно, что интерпретация, по сравнению с прямым выполнением, на 1-2 порядка медленнее. Применение компиляции "на лету" и специализированных Java-процессоров, несомненно, улучшит ситуацию, но пока использование Java на серверной стороне представляется проблематичным.
Хотя технология Интранет, основанная на использовании Web-сервиса в качестве информационной основы организации, является огромным шагом вперед, существуют и другие сервисы, как унаследованные, так и современные (например, реляционные СУБД), которые обязательно должны входить в состав корпоративной системы.
Риc. 5. Прямая связь между Java-клиентами и корпоративными серверами
Если вся связь между клиентами и упомянутыми серверами будет осуществляться через сервер WWW, последний станет узким местом, а решения Интранет рискуют лишиться такого важнейшего достоинства, как масштабируемость. Значит, необходима прямая связь между клиентскими системами, написанными на языке Java, и произвольными сервисами.
Как реализовать такую связь?
В общем виде ответ очевиден - нужны средства для полноценной интеграции Java в распределенную объектную среду. На серверной стороне компания Sun Microsystems имеет соответствующую технологию - NEO (NEtworked Objects, сетевые объекты). технология NEO удовлетворяет спецификациям OMG (Object Management Group), являющимся промышленным стандартом. При реализации корпоративных информационных систем с использованием NEO наиболее естественным представляется использование трехуровневой архитектуры с серверами приложений, построенными на объектных принципах, на втором уровне и с базовыми и унаследованными серверами на третьем уровне.
Рис.6. Трехуровневая архитектура корпоративной информационной структуры.
К сожалению, столь общий ответ никак не помогает осуществлять прямую связь между Java-клиентом и NEO-сервером. Конечно, можно воспользоваться стандартными средствами программирования в сетевой среде (а Java допускает использование библиотек, написанных на C/C++, равно как и вставку машинных кодов), но если бы это было единственной возможностью, Java рисковала остаться на уровне "оживлялок".
В конце марта компания SunSoft объявила о появлении нового продукта с именем Joe, как раз и предназначенного для существенного облегчения встраивания Java-клиентов в информационные системы Интранет, построенные в трехуровневой архитектуре с использованием среды NEO.
Риc. 7. Распределение ролей между Java, Joe и Neo.
Таким образом, сложилась полная и изумительно красивая картина организации современных Интранет-систем.
JAVA - ЯЗЫК И ТЕХНОЛОГИЯ.
Мобильность Java.
Язык программирования С является мобильным. Это нужно понимать в том смысле, что имеется принципиальная возможность переноса программ C на различные платформы.
Однако следует отметить, что создание приложений, действительно работающих на разных платформах - непростая задача. К сожалению, дело не ограничивается необходимостью перекомпиляции исходного текста программы для работы в другой среде. Много проблем возникает с несовместимостью программных интерфейсов различных операционных систем и графических оболочек, реализующих пользовательский интерфейс.
Вот хотя бы проблемы, связанные с переносом 16-разрядных приложений Windows в 32-разрядную среду Windows 95 и Windows NT. Даже если тщательно следовать всем рекомендациям, разрабатывая приложения так, чтобы они могли работать в будущих версиях Windows, едва ли удастся просто перекомпилировать исходные тексты, не изменив в них ни строчки. Ситуация еще больше ухудшается, если нужно, например, перенести исходные тексты приложения Windows в среду операционной системы OS/2 или в оболочку X-Windows операционной системы UNIX. А ведь есть еще другие компьютеры и рабочие станции!
Как нетрудно заметить, даже если стандартизовать язык программирования для всех платформ, проблемы совместимости с программным интерфейсом операционной системы значительно усложняют перенос программ на различные платформы. И, конечно, нужно, чтобы загрузочный модуль одной и той же программы мог работать без изменений в среде различных операционных систем и на различных платформах. Если программа подготовлена для процессора Intel, она ни за что не согласится работать на процессоре Alpha или каком-либо другом.
В результате создавая приложение, способное работать на различных платформах, необходимо фактически делать несколько различных приложений и сопровождать их по отдельности.
Покажем, как приложение, изначально разработанное для Windows NT, переносится на платформу Apple Macintosh. Вначале программист готовит исходные тексты приложения для платформы Windows NT и отлаживает их там. Для получения загрузочного модуля исходные тексты компилируются и редактируются. Полученный в результате загрузочный модуль может работать на процессоре фирмы Intel в среде операционной системы Windows NT.
Для того чтобы перенести приложение в среду операционной системы компьютера Macintosh, программист вносит необходимые изменения в исходные тексты приложения. Эти изменения необходимы из-за различий в программном интерфейсе операционной системы Windows NT и операционной системы, установленной в Macintosh. Далее эти исходные тексты транслируются и редактируются, в результате чего получается загрузочный модуль, способный работать в среде Macintosh, но не способный работать в среде Windows NT.
Программа на языке Java компилируется в двоичный модуль, состоящий из команд виртуального процессора Java. Такой модуль содержит байт-код, предназначенный для выполнения Java-интерпретатором. На настоящий момент уже созданы первые модели физического процессора, способного выполнять этот байт-код, однако интерпретаторы Java имеются на всех основных компьютерных платформах. Разумеется, на каждой платформе используется свой интерпретатор, или, точнее говоря, свой виртуальный процессор Java.
Если приложение Java (или аплет) должно работать на нескольких платформах, нет необходимости компилировать его исходные тексты несколько раз. Можно откомпилировать и отладить приложение Java на одной, наиболее удобной для вас платформе. В результате вы получите байт-код, пригодный для любой платформы, где есть виртуальный процессор Java. Таким образом, приложение Java компилируется и отлаживается только один раз, что уже значительно лучше. Остается, правда, вопрос - как быть с программным интерфейсом операционной системы, который отличается для разных платформ?
Приложение Java не обращается напрямую к интерфейсу операционной системы. Вместо этого оно пользуется готовыми стандартными библиотеками классов, содержащими все необходимое для организации пользовательского интерфейса, обращения к файлам, для работы в сети и так далее.
Внутренняя реализация библиотек классов зависит от платформы. Однако все загрузочные модули, реализующие возможности этих библиотек, поставляются в готовом виде вместе с виртуальной машиной Java, поэтому программисту не нужно об этом заботиться. Для операционной системы Windows, например, поставляются библиотеки динамической загрузки DLL, внутри которых запрятана вся функциональность стандартных классов Java.
Абстрагируясь от аппаратуры на уровне библиотек классов, программисты могут больше не заботиться о различиях в реализации программного интерфейса конкретных операционных систем. Это позволяет создавать по-настоящему мобильные приложения, не требующие при переносе на различные платформы перетрансляции и изменения исходного текста.
Еще одна проблема, возникающая при переносе программ, составленных на языке программирования С, заключается в том, что размер области памяти, занимаемой переменными стандартных типов, различный на разных платформах. Например, в среде операционной системы Windows версии 3.1 переменная типа int в программе, составленной на С, занимает 16 бит. В среде Windows NT этот размер составляет 32 бита.
Очевидно, что трудно составлять программу, не зная точно, сколько имеется бит в слове или в байте. При переносе программ на платформы с иной разрядностью могут возникать ошибки, которые трудно обнаружить.
В языке Java все базовые типы данных имеют фиксированную разрядность, которая не зависит от платформы. Поэтому программисты всегда знают размеры переменных в своей программе.
ОБЪЕКТНАЯ МОДЕЛЬ ЯЗЫКА JAVA.
Когда говорят об объектно-ориентированном языке программирования, предполагают поддержку трех механизмов:
инкапсуляция
наследование
полиморфизм.
Инкапсуляция и наследование в языке Java реализуются с помощью понятия класса.
КЛАССЫ.
Для создания классов можно использовать только ключевое слово class. Что же касается union, то это ключевое слово в Java не применяется. В языке программирования С++ описание класса может быть отделено от его определения. Для Java это не так - описание класса недопустимо. Все методы должны быть определены внутри определения класса. Недопустимо определение вложенных классов.
В Java также нет шаблонов. Возможно создавать классы только на базе других классов. Объект класса создается при помощи ключевого слова new, однако невозможно удалить объект явным образом, так как ключевое слово delete языка программирования С++ в Java не используется.
При определении класса нельзя указать деструктор. Функции удаления объектов Java из памяти выполняет система сборки мусора. Внутри одного исходного файла можно определить только один общедоступный класс public.
Все классы в Java наследуются от класса Object, поэтому для любого объекта можно использовать методы этого класса.
1 class Point extends Object {
2 private double x;
3 private double y;
4 Point (double x, double y) {
5 this.x = x;
6 this.y = y;
7 }
8 Point () {
9 this (0.0, 0.0);
10 }
11 public void setX (double x) {
12 this.x = x;
13 }
14 public void setY (double y) {
15 this.y = y;
16 }
. . .
17 }
Класс является шаблоном для создания объектов; он может содержать данные и методы. Выше приведен пример класса, описывающего точки в двумерном пространстве. Здесь и далее номера строк используются для последующих пояснений и не являются частью Java-программ.
В языке Java нельзя отрывать определение метода (функции) от описания заголовка. Синтаксическая конструкция class полностью включает в себя всю информацию о классе. В частности, реализации методов обязаны содержаться внутри этой конструкции.
Для обозначения наследования используется ключевое слово extends (строка 1). Класс Object - это корень дерева наследования. В Java не бывает классов-"сирот": у всех классов, кроме Object, есть предшественник.
Режимы доступа к элементам класса (private, protected, public) те же, что и в C++, за одним важным исключением. Если режим доступа опущен, предполагается, что соответствующий элемент доступен в пределах пакета (см. далее).
В строке 9 приведен пример явного вызова одного конструктора из другого.
Прочие приведенные выше строки не нуждаются в пояснениях кроме одной - отсутствующей. В языке Java не бывает деструкторов. Причина в том, что управление памятью автоматизировано (в фоновом режиме работает сборщик мусора). Для высвобождения прочих ресурсов, ассоциированных с объектом, служит специальный метод finalize. Этот метод вызывается сборщиком мусора в момент утилизации памяти, занимаемой объектом.
1 class Point3D extends Point {
2 protected double z;
3 Point3D () {
4 super ();
5 z = 0.0;
6 }
7 Point3D (double x, double y, double z) {
8 super (x, y);
9 this.z = z;
10 }
11 }
Ключевое слово this (см., например, строки 5 и 9) используется в объекте для ссылки на самого себя. Аналогичную роль по отношению к родительскому классу играет слово super. В строках 4 и 8 вызываются конструкторы родительского класса.
Приведенные примеры показывают, что в языке Java, как и в C++, методы могут быть перегруженными, то есть под одним именем могут фигурировать разные методы с разным набором параметров. Вы не можете определять методы вне тела класса, создавая таким образом глобальные функции. Нет также возможности определения вне класса глобальных данных. Тем не менее, внутри класса можно определять статические методы и поля (с помощью ключевого слова static), которые будут играть роль глобальных методов и данных.
Пользуясь ключевыми словами static и final, можно определять внутри классов глобальные константы.
Если в базовом классе метод определен с ключевым словом final, его нельзя переопределить в дочернем классе, созданном на базе данного метода.
Методы не могут быть определены как inline.
Методы Java могут создавать исключения, вызванные возникновением ошибок или других событий. Все исключения должны либо обрабатываться внутри метода, либо описываться в определении метода после ключевого слова throws.
1 public native String getName();
2 public native Class getSuperclass();
3 public static native Class forName(String className) throws ClassNotFoundException;
Как и в C++, с помощью ключевого слова static можно определить данные и методы, которые являются общими для всех объектов класса. (Функций, не принадлежащих какому-либо классу, в языке Java не бывает.) Следующий пример содержит фрагменты стандартного пакета java.lang.
Прокомментируем этот пример с точки зрения отличий Java от C++.
Строки с 5 по 21 представляют собой инициализацию статических данных класса, которая осуществляется в момент загрузки класса в Java-машину. По сути этот код играет роль конструктора класса Character.
В строках 1 и 3 встречается ключевое слово final. В строке 1 это слово обозначает запрет на наследование от класса Character. В строке 3 его смысл аналогичен описателю const в C++.
Если слово final использовано в заголовке метода, то данный метод не может быть переопределен в классах-наследниках.
Как и в C++, в языке Java классы могут быть абстрактными, то есть не до конца конкретизированными. Это означает, что в классе описаны методы, определения которых отсутствуют. Такие методы (как и сам класс) должны снабжаться описателем abstract. Абстрактные методы должны конкретизироваться в производных классах.
В языке Java имеется предопределенная иерархия классов, содержащихся в пакете java.lang. В этой иерархии несколько особняком стоит класс Class. Программист не может создать объект класса Class (правда, существуют и другие классы с этим свойством). Ссылки на объект класса Class можно получить с помощью метода getClass, определенного для объектов класса Object.
1 public final
2 class Character extends Object {
3 public static final int MAX_RADIX = 36;
4 static char downCase[];
5 static {
6 char down[] = new char[256];
7 for (int i = 0 ; i < 256 ; i++) {
8 down[i] = (char) i;
9 }
10 for (int lower = 'a' ; lower <= 'z' ; lower++) {
11 int upper = (lower + ('A' - 'a'));
12 down[upper] = (char)lower;
13 }
14 for (int lower = 0xE0; lower <= 0xFE; lower++) {
15 if (lower != 0xF7) {
16 int upper = (lower + ('A' - 'a'));
17 down[upper] = (char)lower;
18 }
19 }
20 downCase = down;
21 }
22 public static boolean isLowerCase(char ch) {
23 return (upCase[ch] != ch);
24 }
25 }
Объекты класса Class используются для получения во время выполнение информации о "классовых" свойствах объекта. К объектам класса Class, помимо прочих, применимы предыдущие методы.
Метод forName позволяет получить ссылку на класс по его имени. Описатель native свидетельствует о том, что метод реализуется средствами, внешними по отношению к Java-системе (например, пишется на языке C).
НАСЛЕДОВАНИЕ. Интерфейсы.
Модель наследования в языке Java существенно отличается от модели C++. Во-первых, в Java нет множественного наследования. Таким образом, для каждого дочернего класса может быть только один базовый класс. При необходимости, однако, этот дочерний класс может реализовывать произвольное количество интерфейсов. Для ссылки на методы базового класса вы должны использовать ключевое слово super.
При необходимости можно вызвать в первой исполняемой строке конструктора дочернего класса конструктор базового класса (опять же с помощью ключевого слова super).
Во-вторых, в языке предусмотрены средства для запрета дальнейшего наследования (ключевое слово final перед определением класса). В-третьих, в языке Java присутствует новое по отношению к C++ понятие интерфейса. Интерфейсы создаются при помощи ключевого слова interface таким же образом, что и классы. Однако в отличие от последних, интерфейсы являются аналогом абстрактных базовых классов без полей данных и предназначены только для определений набора методов для решения каких-либо задач, например, добавления компонент в контейнеры, организации списков, сортировки и так далее.
Можно создать свой класс на базе другого класса, указав при этом с помощью ключевого слова implements, что он реализует тот или иной интерфейс. При этом наряду с методами базового класса в созданном таким образом классе будут доступны методы, определенные в интерфейсе.
public interface Verbose {
public void drawOn (Graphics g);
public void printOn (OutputStream os);
}
public class Star extends Polygon implements Verbose {
public void drawOn (Graphics g) {
// Конкретная реализация отрисовки
}
public void printOn (OutputStream os) {
// Конкретная реализация печати
}
}
public class Text extends StringBuffer implements Verbose {
public void drawOn (Graphics g) {
// Конкретная реализация отрисовки
}
public void printOn (OutputStream os) {
// Конкретная реализация печати
}
}
public class Blackboard extends Canvas {
public void drawVerbose (Verbose d) {
Graphics g = getGraphics ();
d.drawOn (g);
}
}
Интерфейс представляет собой набор описаний методов. Этот пример был описан только что. Интерфейс Verbose содержит два метода. Первый предназначен для рисования в графическом контексте, второй - для распечатки в выходной поток.
Класс Star представляет собой подкласс многоугольников (Polygon). Помимо прочего, мы хотим рисовать объекты этого класса на доске (Blackboard) и выводить их описание в файл.
Для объектов класса Text мы хотим иметь возможность начертать текст на доске и выводить его в файл.
Класс Blackboard - наследник класса Canvas, специально предназначенного для рисования. Как мы видим, этот класс с помощью единственного метода справляется с рисованием объектов, не имеющих общего предка (кроме класса Object).
Таким образом, с помощью интерфейсов можно компенсировать отсутствие множественного наследования. В контексте наследования интерфейс можно рассматривать как абстрактный класс, не содержащий данных.
ЖИЗНЕННЫЙ ЦИКЛ ОБЪЕКТА.
Объекты создаются с помощью оператора new. Инициализация объекта производится с помощью соответствующего конструктора. Эти операции разделить нельзя - за new всегда следует конструктор. Пример:
Point myPoint = new Point ();
Других способов создания объектов (кроме оператора new) язык Java не предоставляет.
Объект существует до тех пор, пока на него есть ссылки (то есть пока он прямо или косвенно доступен хотя бы из одной переменной). В языке отсутствуют явные средства удаления объектов. После того, как объект стал недоступен, он оказывается кандидатом для утилизации сборщиком мусора.
Point p = new Point (100.0, 100.0);
. . .
p = new Point (1.0, 1.0);
// На точку с координатами (100, 100) ссылок больше нет
{
String s = new String ("Local string");
System.out.println (s);
}
// На строку "Local string" ссылок больше нет
Объект может стать недоступным, если хранившей его переменной присвоено новое значение или если эта переменная перестала быть доступной (произошел выход из блока). Пример приведен выше. В момент утилизации объекта сборщиком мусора будет вызван метод finalize. Из-за того, что сборщик мусора работает в фоновом режиме, вызов finalize является асинхронным.
Базовые типы данных.
В языке Java определено восемь базовых типов данных. Для каждого базового типа данных отводится конкретный размер памяти. Этот размер не зависит от платформы, на которой выполняется приложение Java:
Тип данных |
Размер занимаемой области памяти |
Значение по умолчанию |
boolean |
8 |
false |
byte |
8 |
0 |
char |
16 |
'x0' |
short |
16 |
0 |
int |
32 |
0 |
long |
64 |
0 |
float |
32 |
0.0F |
double |
64 |
0.0D |
Фактически размеры памяти, отведенные для хранения переменной, могут отличаться от приведенных выше, например, для хранения переменной типа short может быть зарезервировано слово размером 32 бита. Однако язык Java сделан таким образом, что это никак не повлияет на мобильность приложения. Так как в языке Java нет указателей, нельзя адресоваться к элементам массива чисел по относительному смещению этих элементов в оперативной памяти. Следовательно, точный размер элемента в данном случае не играет никакой роли.
Все базовые типы данных по умолчанию инициализируются, поэтому программисту не нужно об этом беспокоиться. Можно также инициализировать переменные базовых типов в программе или при их определении, как это показано ниже:
int nCounter = 0;
int i;
i = 8;
Переменные типа boolean могут находиться только в двух состояниях - true и false, причем эти состояния никаким образом нельзя соотнести с целыми значениями. Вы не можете, как это было в языке С, выполнить преобразование типа boolean, например, к типу int - компилятор выдаст сообщение об ошибке.
Переменная типа byte занимает восемь бит памяти и про нее больше нечего сказать.
Что же касается типа char, то он используется для хранения символов в кодировке UNICODE. Эта кодировка позволяет хранить национальные наборы символов, что очень удобно для интернациональных приложений, предназначенных для работы в Internet.
Переменные типа byte, short, int и long являются знаковыми. В языке Java нет беззнаковых переменных, как это было в языке С.
Приложение Java может оперировать числами в формате с плавающей точкой, определенным в спецификации IEEE 754. Тип float позволяет хранить числа с одинарной точностью, а формат double - с двойной.
Переменные базовых типов могут передаваться функциям в качестве параметров только по значению, но не по ссылке. Поэтому следующий фрагмент кода работать не будет:
int x;
void ChangeX(int x)
{
x = 5;
}
. . .
x = 0;
ChangeX(x);
После вызова функции ChangeX содержимое переменной x останется равным нулю.
Проблему можно решить, если вместо базовых переменных использовать объекты встроенных классов, соответствующие базовым переменным.
Массивы в Java.
В языке Java присутствуют массивы. Эти массивы типизированы. Декларация
Point myPoints[];
описывает переменную myPoints как массив объектов типа Point. Завести массив определенного размера можно с помощью инструкции вида
myPoints = new Point[10];
Значения элементов массива при этом устанавливаются равными специальной величине null.
Размер массива может быть получен во время выполнения программы:
howMany = myPoints.length;
Для создания массива вы можете пользоваться квадратными скобками, расположив их справа от имени массива или от типа объектов, из которых составлен массив, например:
int nNumbers[];
int[] nAnotherNumbers;
Допустимы оба варианта, поэтому вы можете выбрать тот, который вам больше нравится.
При определении массивов в языке Java нельзя указывать их размер. Приведенные выше две строки не вызывают резервирования памяти для массива. Здесь просто создаются ссылки на массивы, которые без инициализации использовать нельзя.
Для того чтобы заказать память для массива, вы должны создать соответствующие объекты с помощью ключевого слова new, например:
int[] nAnotherNumbers;
nAnotherNumbers = new int[15];
Как выполнить инициализацию ячеек таблицы?
Такую инициализацию можно выполнить либо статически, либо динамически. В первом случае вы просто перечисляете значения в фигурных скобках, как это показано ниже:
int[] nColorRed = {255, 255, 100, 0, 10};
Динамическая инициализация выполняется с использованием индекса массива, например, в цикле:
int nInitialValue = 7;
int[] nAnotherNumbers;
nAnotherNumbers = new int[15];
for(int i = 0; i < 15; i++)
{
nAnotherNumbers[i] = nInitialValue;
}
Возможно создавать массивы не только из переменных базовых типов, но и из произвольных объектов. Каждый элемент такого массива должен инициализироваться оператором new.
Массивы могут быть многомерными и, что интересно, несимметричными.
Ниже создается массив массивов. В нулевом и первом элементе создается массив из четырех чисел, а во втором - из восьми:
int[][] nDim = new int[5][10];
nDim[0] = new int [4];
nDim[1] = new int [4];
nDim[2] = new int [8];
Во время выполнения приложения виртуальная машина Java проверяет выход за границы массива. Если приложение пытается выйти за границы массива, происходит исключение.
Массивы в языке Java являются объектами некоторого встроенного класса. Для этого класса существует возможность определить размер массива, обратившись к элементу данных класса с именем length, например:
int[] nAnotherNumbers;
nAnotherNumbers = new int[15];
for(int i = 0; i < nAnotherNumbers.length; i++)
{
nAnotherNumbers[i] = nInitialValue;
}
Для определения размера массива вам не нужен такой оператор, как sizeof из языка программирования С, потому что существует другой способ определения этого размера.
Других структурных типов (не являющихся объектами) в языке Java нет, то есть нет структур, объединений и т.п. Нет в Java и указателей.
Строки символов являются объектами типа String (текстовые константы) или StringBuffer (изменяемые строки). Пример:
String hello = "Hello world!";
ПАКЕТЫ.
Классы в языке Java объединяются в пакеты. Все классы, входящие в один пакет, являются дружественными по отношению друг к другу, то есть имеют взаимный доступ к переменным и методам, если противное не оговорено явно посредством спецификаторов private или protected.
Пакеты разграничивают пространства имен. "Просто глобальных" имен в языке Java не бывает.
Пакет оформляется с помощью синтаксической конструкции вида
package my_packages.pack1:
Инструкция package должна стоять первой в файле с исходным Java-текстом. Она действует до конца файла.
Пакеты могут импортироваться другими пакетами посредством инструкции import. Примеры,
import java.util;
import java.util.HashTable;
import java.util.*;
Первая инструкция import позволяет обращаться к классам пакета util следующим образом:
util.Vector
util.HashTable
. . .
Вторая инструкция импортирует лишь класс HashTable, позволяя в дальнейшем обращаться к этому классу по короткому имени, без префикса util.
Третья инструкция import позволяет обращаться по коротким именам ко всем классам пакета util.
УПРАВЛЯЮЩИЕ КОНСТРУКЦИИ.
Управляющие конструкции языка Java вполне традиционны, за исключением средств выхода из вложенных блоков (в частности, из вложенных циклов). Пример:
test:
for
(int i = 0; i < 10; i++) {
for
(int j = 0; j < 10; j++) {
if
(i > 3) {
break
test;
}
}
}
Для передачи управления можно применять как конструкцию break, так и continue (переход к следующей итерации цикла).
Инструкция goto в языке Java отсутствует.
ИСКЛЮЧИТЕЛЬНЫЕ СИТУАЦИИ.
Для обработки исключительных ситуаций, возникающих во время выполнения программы, в языке Java используется конструкция try/catch/finally. Блок try содержит инструкции, выполнение которых может привести к возникновению исключительных ситуаций. Следующие за ним один или несколько блоков catch предназначены для обработки исключительных ситуаций. Наконец, блок finally содержит инструкции, которые будут выполнены независимо от возникновения исключительной ситуации в блоке try. При выходе из try-части посредством инструкций передачи управления (break, return и т.п.) блок finally также будет выполнен.
Для передачи информации об исключительной ситуации используются объекты классов - наследников класса Throwable. Например, класс ArrayIndexOutOfBoundsException отвечает за контроль выхода индексов за границы массивов, класс OutOfMemoryException - за реакцию на исчерпание свободной памяти, класс ClassCastException - за ошибки при преобразовании типов, класс InterruptedException - за обработку прерывания текущего потока и т.д. Компонентой всех этих классов является поле типа String, в которое помещается текст сообщения об ошибке. Метод getMessage возвращает этот текст.
В подобных объектах может содержаться и дополнительная информация. Например, объекты класса InterruptedIOException содержат поле, в которое заносится число байт, переданных до возникновения исключительной ситуации.
try {
for (int i = 0; i < 100; i++) {
System.out.println (messages[i]);
}
}
catch (ArrayOutOfBoundException e) {
System.out.println ("No more messages");
}
catch (Exception e) {
System.out.println ("Unexpected exception");
System.out.println (e.getMessage());
}
finally {
System.out.println ("Work done");
}
Фрагмент программы, показанный выше, распечатывает сообщения из массива messages. При этом мы не пытаемся выяснить размер массива, а просто полагаемся на механизм обработки исключительных ситуаций. (Конечно, мы не советуем писать программы в таком стиле).
Исключительные ситуации могут возбуждаться программно при помощи инструкций вида
throw new MyException ( "Something's wrong");
Спецификации языка Java подразделяют исключительные ситуации на две категории. К первой категории (класс Error) относятся ситуации, на которые программа не обязана реагировать (это заведомо сделает Java-машина). Ко второй категории (класс Exception) относятся ситуации, которые программа должна обрабатывать обязательно. Если при выполнении метода может возникать исключительная ситуация второго типа, он должен либо обрабатывать ее сам с помощью конструкции try/catch/finally, либо в его определении должна фигурировать конструкция throws Exception1, Exception2, ...
class Foo extends Object {
. . .
public void readFromFile (String fn) throws InvalidFormatException {
FileInputStream fis;
try {
fis = new FileInputStream (fn);
// Читаем данные из файла.
. . .
// Если файл имеет неправильный формат,
// вожбуждаем исключительную ситуацию:
throw new InvalidFormatException ("Wrong format");
. . .
}
catch (FileNotFoundException e) {
// Предпринимаем соответствующие действия
}
finally {
if (fis != null )
fis.close(); // всегда закрываем файл, если он был открыт
}
}
. . .
}
В этом примере, в методе readFromFile могут возникнуть две исключительные ситуации. Первая связана с тем, что нужный файл недоступен. Эта ситуация обрабатывается внутри метода readFromFile. Вторая исключительная ситуация может возникнуть, если файл имеет неправильный формат. Эта ситуация передается для обработки наверх.
МЕХАНИЗМ ПОТОКОВ.
Механизм потоков - обязательная черта современных операционных сред. За счет потоков обеспечивается масштабируемость программных систем, оптимальное использование аппаратных ресурсов, высокая скорость отклика на запросы пользователей. Нет ничего удивительного в том, что в языке Java механизм потоков предусмотрен с самого начала и в полном объеме.
В языке Java потоки представлены посредством класса Thread, интерфейса Runnable, спецификатора метода synchronized и методов класса Object wait и notify.
КЛАСС THREAD И ИНТЕРФЕЙС RUNNABLE
Поток (thread) представляет собой отдельный поток управления в пределах процесса. Таким образом, у каждого потока есть начало, последовательность действий, текущее состояние и конец.
Поток запускается с помощью вызова метода start() класса Thread. Последовательность действий, выполняемых в рамках потока, задается в методе run(). Подчеркнем, что метод run() используется только для задания последовательности действий; явно вызывать его не только не нужно, но и просто вредно.
Поток заканчивается либо при завершении выполнения метода run(), либо с помощью явных вызовов методов класса Thread stop() или destroy(). Возобновить работу завершенного потока невозможно.
Для временной приостановки работы потока с последующим возобновлением служат методы suspend(), sleep() и yeild().
Обычно поток, приостановленный с помощью метода suspend, возобновляет работу посредством метода resume().
Вызов метода sleep() приводит к приостановке потока на заданное число миллисекунд.
Вызов метода yeild() означает добровольную уступку процессора другому потоку; первоначальный поток остается готовым к выполнению.
Java-потоки обладают приоритетами. В спецификациях оговаривается, что Java-машина реализует вытесняющую многопотоковость. Это означает, что поток с большим приоритетом может прервать выполнение менее приоритетного потока. Однако, спецификации не требуют наличия разделения времени. Это значит, что для передачи управления потоку с тем же приоритетом, вообще говоря, требуются явные действия со стороны первоначального потока - вызов методов suspend(), sleep() или yeild().
class my_producer extends Thread
{
int items_to_do ;
my_buffer the_buffer ;
my_producer (my_buffer buf, int count)
{ super() ;
the_buffer = buf ;
items_to_do = count ;
}
public void run ()
{
while (items_to_do > 0)
{ System.out.println ("producer to_do = " + items_to_do) ;
Integer item = new Integer (items_to_do*items_to_do) ;
the_buffer.insert (item) ;
items_to_do- ;
}
System.out.println ("producer exiting") ;
}
}
Этот пример содержит фрагмент одного из многочисленных вариантов решения задачи "производитель/ потребитель". Он заимствован из письма, которое написал Mark Tillotson в группу сетевых новостей comp.lang.java.
Данный производитель помещает в буфер квадраты целых чисел.
1 class SomethingToRun extends BaseRunner implements Runnable {
2 private Thread aThread;
3 public void run () {
// выполняемые действия
. . .
4 }
5 SomethingToRun () {
6 aThread = new Thread (this);
7 aTread.start ();
8 }
9 }
В приведенном простом примере класс my_producer является наследником класса Thread, что делает его потоком с последовательностью действий, заданной методом run(). В реальных программах, как правило, объект должен наследовать у какого-либо предшественника содержательные свойства, а возможность параллельного выполнения ему предоставляется интерфейсом Runnable. Этот интерфейс содержит единственный метод - run().
В строке 6 создается новый поток. Аргументом конструктора является объект класса SomethingToRun, а, значит, последовательность выполняемых действий потока будет определяться методом run() этого класса. Вызов метода start() в строке 7 ставит поток в очередь готовых для выполнения.
СРЕДСТВА СИНХРОНИЗАЦИИ ПОТОКОВ
Как и во всякой многопроцессной или многопотоковой среде, в Java существует проблема синхронизации доступа к разделяемым ресурсам. Примером такого ресурса является буфер в задаче "производитель/потребитель".
Для опытных программистов отметим, что модель синхронизации, принятая в языке Java, опирается на концепцию монитора, предложенную в 70-е годы Бринк-'ансеном.
В Java-программах можно выделять критические интервалы, которые обозначаются ключевым словом synchronized. Если критическим интервалом является метод, спецификатор synchronized помещается в его (метода) заголовок. Для превращения произвольной инструкции (обычно это блок) в критический интервал служит конструкция
synchronized (выражение) инструкция;
где результатом выражения должен быть объект или массив.
Выполнение критического интервала начинается только после получения потоком монопольного доступа к соответствующему объекту или массиву. До наступления этого момента поток блокируется.
class my_buffer
{
Object [] vec = new Object [8] ;
int ip = 0 ;
int ep = 0 ;
synchronized void insert (Object item)
{
do
{
if (ip-ep < 8)
{ vec [(ip++) & 7] = item ;
if (ip-ep == 1) notify () ; // Уведомить, если буфер
// был пуст
return ;
}
try wait () ; catch (InterruptedException e) ;
} while (true) ;
}
synchronized Object extract ()
{
do
{
if (ip > ep)
{ Object result = vec [(ep++) & 7] ;
if (ip-ep == 7) notify () ; // Уведомить, если
//буфер был полон
return result ;
}
try wait () ; catch (InterruptedException e) ;
} while (true) ;
}
}
class my_producer extends Thread
{
int items_to_do ;
my_buffer the_buffer ;
my_producer (my_buffer buf, int count)
{ super() ;
the_buffer = buf ;
items_to_do = count ;
}
public void run ()
{
while (items_to_do > 0)
{ System.out.println ("producer to_do = " + items_to_do) ;
Integer item = new Integer (items_to_do*items_to_do) ;
the_buffer.insert (item) ;
items_to_do- ;
}
System.out.println ("Производитель заканчивает"
+ " работу") ;
}
}
class my_consumer extends Thread
{
int items_to_do ;
my_buffer the_buffer ;
my_consumer (my_buffer buf, int count)
{ super() ;
the_buffer = buf ;
items_to_do = count ;
}
public void run ()
{
while (items_to_do > 0)
{ System.out.println ("consumer to_do = " + items_to_do) ;
Object item = the_buffer.extract () ;
System.out.println ("consumer got " + item) ;
items_to_do- ;
}
System.out.println ("Потребитель заканчивает работу") ;
synchronized (this){
notify () ; // Посылаем уведомление о завершении
// работы (см. con.wait() в main())
}
}
}
public class threaded3
{
public static void main (String [] args) throws
InterruptedException
{
my_buffer the_buffer = new my_buffer () ;
my_producer prod = new my_producer (the_buffer, 40) ;
my_consumer con = new my_consumer (the_buffer, 40) ;
Thread.currentThread().setPriority (5) ;
prod.setPriority (4) ; // Производитель получает более
// высокий приоритет
con.setPriority (3) ; // по сравнению с потребителем
prod.start() ;
con.start() ;
synchronized (con)
{
con.wait() ; // Ждем уведомления от производителя
//об окончании его работы
}
System.out.println ("Производитель и потребитель"
+" закончили работу") ;
}
}
Вызов wait() внутри критического интервала приводит к тому, что текущий поток уступает монопольное право на критический интервал и приостанавливается до тех пор, пока из какого-либо другого потока не будет сделан вызов notify() или notifyAll(). Хорошей иллюстрацией использования средств синхронизации потоков является упоминавшаяся только что программа Марка Уиллотсона.
Приведенная программа написана в очень хорошем, понятном стиле. В методах insert() и extract() класса my_buffer вызов wait() содержится внутри бесконечного цикла. Дело в том, что вызов notify() относится к объекту в целом. "Разбуженный" объект должен проанализировать свое состояние и решить, что делать дальше. Так, если "заснул" метод insert(), то после возобновления работы необходимо проверить, что буфер уже не полон и добавление нового элемента стало возможным. Если это не так, метод insert() заснет вновь.
Библиотеки классов Java
Если предоставить в распоряжение программиста только язык программирования и не снабдить его набором готовых модулей, предназначенных для решения самых распространенных задач, ему придется отвлекаться на множество мелких деталей.
Обычно все профессиональные системы разработки приложений на языке программирования C++ содержат в своем составе набор стандартных библиотечных функций или библиотеки классов. В комплекте со всеми средствами разработки Java поставляются достаточно развитые библиотеки классов, значительно упрощающие программирование. В этом разделе мы кратко расскажем о составе и назначении библиотек классов Java.
Встроенные классы.
В языке Java все классы происходят от класса Object, и, соответственно, наследуют методы этого класса. Некоторые библиотеки классов подключаются автоматически, и мы будем называть их встроенными. К таким относится, в частности, библиотека с названием java.lang. Другие библиотеки классов вы должны подключать в исходном тексте приложения Java явным образом с помощью оператора import.
Замещающие классы.
Очень часто в наших приложениях вместо базовых типов переменных мы будем использовать объекты встроенных классов, которые называются замещающими классами (wrapper classes). Ниже мы перечислили названия этих классов и названия базовых типов данных, которые они замещают:
Базовый тип данных |
Замещающий класс |
boolean |
Boolean |
char |
Character |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
Заметим, что для преобразования базовых типов данных в объекты замещающего класса и обратно нельзя применять оператор присваивания. Вместо этого необходимо использовать соответствующие конструкторы и методы замещающих классов.
Класс String.
Класс String предназначен для работы с такими часто встречающимися объектами, как текстовые строки. Методы этого класса позволяют выполнять над строками практически все операции, которые вы делали раньше при помощи библиотечных функций C. Это преобразование строки в число и обратно с любым заданным основанием, определение длины строки, сравнение строк, извлечение подстроки и так далее.
Хотя в языке Java не допускается перезагрузка (переопределение) операторов, для объектов класса Stirng и объектов всех произошедших от него классов сделана встроенная перезагрузка операторов "+" и "+=". С помощью этих операторов можно выполнять слияние текстовых строк, например:
System.out.println("x = " + x + '\n');
Здесь в качестве параметра функции println передается текстовая строка, составленная из трех компонент: строки "x = ", числа x и символа перехода на следующую строку '\n'. Значение переменной x автоматически преобразуется в текстовую строку (что выполняется только для текстовых строк) и полученная таким образом текстовая строка сливается со строкой "x = ".
Другие встроенные классы.
Среди других встроенных классов отметим класс Math, предназначенный для выполнения математических операций, таких как вычисление синуса, косинуса и тангенса.
Предусмотрены также классы для выполнения запуска процессов и потоков, управления системой безопасности, а также для решения прочих системных задач.
Библиотека встроенных классов содержит очень важные классы для работы с исключениями. Эти классы нужны для обработки ошибочных ситуаций, которые могут возникнуть (и возникают!) при работе приложений или аплетов Java.
Подключаемые библиотеки классов.
Ниже кратко перечислим подключаемые библиотеки классов для того, чтобы можно было оценить возможности набора классов Java. Подробное описание этих классов есть в справочной системе Java WorkShop и в различной литературе, посвященной Java.
Библиотека классов java.util.
Библиотека классов java.util очень полезна при составлении приложений, потому что в ней имеются классы для создания таких структур, как динамические массивы, стеки и словари. Есть классы для работы с генератором псевдослучайных чисел, для разбора строк на составляющие элементы (токены), для работы с календарной датой и временем.
Библиотека классов java.io.
В библиотеке классов java.io собраны классы, имеющие отношение к вводу и выводу данных через потоки. С использованием этих классов можно работать не только с потоками байт, но также и с потоками данных других типов, например числами int или текстовыми строками.
Библиотека классов java.net.
Язык программирования Java разрабатывался в предположении, что им будут пользоваться для создания сетевых приложений. Поэтому было бы странно, если бы в составе среды разработки приложений Java не поставлялась библиотека классов для работы в сети. Библиотека классов java.net предназначена как раз для этого. Она содержит классы, с помощью которых можно работать с универсальными сетевыми адресами URL, передавать данные с использованием сокетов TCP и UDP, выполнять различные операции с адресами IP. Эта библиотека содержит также классы для выполнения преобразований двоичных данных в текстовый формат, что часто бывает необходимо.
В качестве примера приложения, составленного на языке программирования Java и ориентированного на работу в сети Internet, можно привести игру Java Color Lines (рис. 7).
Это сетевая версия известной игры Lines, которая выполнена в виде нескольких аплетов, взаимодействующих между собой и между сервером Web, на котором они расположены. Так как список имен игроков и достигнутых ими результатов хранится на сервере, вы можете поучаствовать в мировом турнире, сразившись с игроками из разных стран.
Библиотека классов java.awt.
Для создания пользовательского интерфейса аплеты Java могут и должны использовать библиотеку классов java.awt. AWT - это сокращение от Abstract Window Toolkit (инструментарий для работы с абстрактными окнами).
Классы, входящие в состав библиотеки java.awt, предоставляют возможность создания пользовательского интерфейса способом, не зависящим от платформы, на которой выполняется аплет Java. Вы можете создавать обычные окна и диалоговые панели, кнопки, переключатели, списки, меню, полосы просмотра, однострочные и многострочные поля для ввода текстовой информации.
Библиотека классов java.awt.image.
В среде любой операционной системы работа с графическими изображениями является достаточно сложной задачей. В операционной системе Windows для этого применяется графический интерфейс GDI. Если вы будете рисовать графические изображения в среде OS/2 или X-Windows, вам, очевидно, придется использовать другой программный интерфейс. Большую сложность также вызывает разбор заголовков графических файлов, так как они могут иметь различный формат и иногда содержат неправильную или противоречивую информацию.
Когда вы программируете на Java, рисование и обработка графических изображений выполняется намного проще, так как вам доступна специально предназначенная для этого библиотека классов java.awt.image. Помимо широкого разнообразия и удобства определенных в ней классов и методов, отметим способность этой библиотеки работать с графическими изображениями в формате GIF. Этот формат широко используется в Internet, так как он позволяет сжимать файлы графических изображений во много раз без потери качества за счет устранения избыточности.
Библиотека классов java.awt.peer.
Библиотека классов java.awt.peer служит для подключения компонент AWT (например, кнопок, списков, полей редактирования текстовой информации, переключателей и так далее) к реализациям, зависящим от платформы, в процессе создания этих компонент.
Библиотека классов java.applet.
Библиотека классов java.applet инкапсулирует поведение аплетов Java. Когда вы будете создавать свои аплеты, вам будет нужен класс Applet, расположенный в этой библиотеке классов. Дополнительно в библиотеке классов java.applet определены интерфейсы для подключения аплетов к содержащим их документам и классы для проигрывания звуковых фрагментов.
ТЕХНОЛОГИЯ JAVA.
ТЕХНОЛОГИЧЕСКИЙ ЦИКЛ ОБРАБОТКИ JAVA-ПРОГРАММ.
Технологический цикл подготовки, трансляции, редактирования внешних связей, тестирования, отладки и выполнения Java-программ тот же, что и для других интерпретируемых языков программирования, но с одним существенным отличием - при редактировании внешних связей требуемые компоненты могут доставляться по сети.
Рис.
8. Технологический цикл обработки
Java-программ
Важно отметить, однако, что Java-программы могут представать как бы в двух ипостасях - как самостоятельное приложение и как аплет, то есть совокупность объектов, выполняющихся в среде WWW-навигатора.
С точки зрения программиста, аплет и приложение отличаются в первую очередь точками входа и жизненным циклом.
Приложение в качестве точки входа имеет метод
public static void main (String args[]);
Этот метод должен быть определен в том public-классе, который содержится в файле, выполняемом виртуальной Java-машиной. В параметр args передается массив строк - параметров командной строки.
Пример: программа, печатающая свои аргументы
public class myTop {
public static void main (String args[]){
int argc = args.length;
for (int i = 0; i < argc; i++)
System.out.println (argc[i]);
}
}
Аплет выполняется в контексте навигатора и его жизненный цикл определяется следующими методами класса Applet:
public void init () - вызывается навигатором при загрузке аплета;
public void start () - вызывается навигатором при показе страницы;
public void stop () - вызывается навигатором, когда тот уходит с Web-страницы;
public void destroy () - этот метод предназначен для освобождения ресурсов; аналог деструктора, но не вызывается автоматически; всегда вызывает stop(); всегда вызывается при выходе из навигатора и при перезагрузке аплета.
1 import java.awt.Graphics;
2 import java.applet.Applet;
3 class SimpleApplet extends Applet {
4 public void paint (Graphics g) {
5 g.drawString (10, 10, "Hello world!");
6 }
7 }
Простейший аплет выглядит так.
Метод paint (строки 4-6) определяет, как аплет перерисовывает себя в тот момент, когда оконный менеджер посылает WWW-навигатору запрос на перерисовку.
Включение аплета в WWW-страницу производится следующим образом. В языке HTML 2.0 предусмотрены специальные конструкции
Если вы видите этот текст, то ваш навигатор не поддерживает Java
Данный фрагмент содержит простой пример включения аплета в WWW-страницу.
Поскольку WWW-навигаторы игнорируют неизвестные конструкции, в навигаторе, не поддерживающем Java, будет виден текст
Если вы видите этот текст, то ваш навигатор не поддерживает Java
public void init () {
String fontname = getParameter ("name");
String fontSizestring = getParameter ("size");
int theSize = Int.parseInt (fontSizeString);
. . .
}
Опросить значения, передаваемые с помощью конструкции , можно следующим образом.
JAVA-МАШИНА.
Java-компилятор транслирует исходные тексты Java-программ в коды Java-машины. Вообще говоря, Java-машина является виртуальной в том смысле, что она не существует в виде реальных микросхем и других устройств, а представляет собой программный эмулятор, выполняющийся на какой-либо традиционной аппаратной платформе. Вероятно, уже в ближайшее время следует ожидать появления и все более широкого распространения и прямых аппаратных реализаций Java-машины.
Идея языковых процессоров не нова. Известны попытки внедрить так называемый P-код в качестве стандарта на результат работы Паскаль-компиляторов; в свое время много писали о языке и машине Форт; была выполнена аппаратная реализация рефал-машины, и список этот можно продолжать и продолжать.
В контексте проекта Java спецификация виртуальной машины является частью комплекса мер, направленных на стандартизацию Java-среды и на обеспечение ее независимости от аппаратно-программной платформы. Кроме того, следует учитывать ту специфическую среду, в которой должны готовиться и работать Java-программы. Если Web-страница содержит Java-аплеты, эти аплеты будут передаваться по сети. Значит, весьма желательно, чтобы Java-код был как можно более компактным; в противном случае время загрузки страницы рискует стать раздражающе большим. Соответственно, архитектура и система команд Java-машины проектировались таким образом, чтобы всячески способствовать компактификации кода. С другой стороны, формат команд Java-машины довольно прост (обычно команды не имеют операндов и занимают один байт), поэтому возможна ее (машины) эффективная эмуляция. По этой причине программы, подготовленные для выполнения на Java-машине, часто называют байт-кодами.
ТИПЫ ДАННЫХ, ПОДДЕРЖИВАЕМЫЕ JAVA-МАШИНОЙ.
Java-машина поддерживает следующие стандартные типы данных:
byte - однобайтные целые числа в двоичном дополнительном коде;
short - двухбайтные целые числа;
int - четырехбайтные целые числа;
long - восьмибайтные целые числа;
float - четырехбайтные вещественные числа в формате IEEE-754;
double - восьмибайтные вещественные числа;
char - двухбайтные беззнаковые символы в кодировке Unicode.
Поскольку Java-компилятор в состоянии проверить типы данных во время трансляции, при выполнении нет нужды ассоциировать дополнительную информацию со значениями стандартных типов. Вместо этого генерируются команды, рассчитанные на обработку данных определенных типов. Например, для сложения целых чисел будет сгенерирована команда iadd, а для сложения вещественных чисел двойной точности - команда dadd.
Значения типа boolean представляются однобайтными целыми числами и обрабатываются посредством соответствующих команд.
Имеется еще два стандартных типа данных:
object - четырехбайтная ссылка на объект (массивы трактуются как объекты);
returnAddress - четырехбайтный адрес возврата из метода.
Спецификации Java-машины не описывают внутренней структуры объектов. В реализации Sun Microsystems значение типа object указывает на описатель, хранящий две ссылки - на таблицу методов и на данные объекта. Возможны и другие представления.
Java-машина является 32-битной. Более длинные значения (long, double) представляются как пара четырехбайтных величин. Не оговаривается, в каком порядке располагаются элементы пары; более того, верификатор байт-кодов обязан выявлять и отвергать программы, пытающиеся "вручную" составлять длинные значения.
РЕГИСТРЫ.
В Java-машине должны поддерживаться следующие регистры:
pc - счетчик команд; указывает на код операции для команды, которая будет выполняться следующей.
vars - базовый регистр для доступа к локальным переменным текущего метода.
optop - указатель на вершину стека операндов. Java-машина является стековой, поэтому основная часть команд берет операнды из стека и туда же помещает результат.
frame - указатель на структуру, содержащую окружение времени выполнения.
В свою очередь, окружение времени выполнения используется для реализации трех целей: динамической загрузки, возврата из методов и обработки исключительных ситуаций.
Для обеспечения динамической загрузки, окружение времени выполнения содержит ссылки на таблицу символов текущего метода и текущего класса. Перед началом выполнения метода производится редактирование его внешних связей (настройка ссылок на внешние методы и внешние данные). Подобная поздняя настройка ссылок делает сгенерированный код устойчивым по отношению к изменениям во внешних классах.
Для обеспечения нормального возврата из методов выполняется восстановление регистрового окружения вызывающего метода.
Для обработки исключительных ситуаций Java-машина выполняет проход по стеку вызовов методов и отыскивает самую внутреннюю конструкцию catch, обрабатывающую случившееся событие.
В принципе окружение времени выполнения может содержать дополнительную информацию, необходимую, например, для отладки, но в спецификациях Java-машины это оставлено на усмотрение авторов реализации.
Указатели, которых нет.
Самая большая новость для тех, кто раньше программировал на С, а теперь занялся изучением Java, это то, что в языке Java нет указателей. Традиционно считалось, что работать с указателями трудно, а их использование приводит к появлению трудно обнаруживаемых ошибок. Поэтому разработчики Java решили отказаться от использования указателей совсем.
Если нужно передать ссылку на переменную базового типа, такого, например, как int или long, то ничего не получится - переменные базовых типов передаются по значению, а не по ссылке. Поэтому нельзя напрямую создать на языке Java эквивалент следующей программы, составленной на языке С:
// Некоторая переменная
int nSomeValue;
// Функция, изменяющая значение переменной,
// заданной своим адресом
void StoreValue(int *pVar, int nNewValue)
{
pVar->nNewValue;
}
. . .
StoreValue(&nSomeValue, 10);
Выход, однако, есть.
Язык Java позволяет использовать вместо указателей ссылки на объекты. Пользуясь этими ссылками, вы можете адресовать объекты по их имени, вызывая методы и изменяя значения данных объектов.
Что же касается данных базовых типов, если вам нужно передавать на них ссылки, то следует заменить базовые типы на соответствующие замещающие классы. Например, вместо типа int используйте класс Integer, вместо типа long - класс Long и так далее.
Инициализация таких объектов должна выполняться с помощью конструктора, как это показано ниже:
Integer nSomeValue;
nSomeValue = new Integer(10);
Первая строка создает неинициализированную ссылку с именем nSomeValue и типом Integer. При попытке использования такой ссылки возникнет исключение.
Вторая строка создает объект класса Integer, вызывая конструктор. Этот конструктор определяет начальное значение. После выполнения оператора присваивания ссылка nSomeValue будет ссылаться на реальный объект класса Integer и ее можно будет использовать.
Имя объекта nSomeValue типа Integer вы можете передавать функциям в качестве параметра, причем это будет ссылкой на объект.
Составляя программы на языке С, часто использовались указатели для адресации элементов массивов, созданных статически или динамически в оперативной памяти. Зная начальный адрес такого массива и тип хранящихся в нем элементов, вы могли адресоваться к отдельным элементам массива.
В языке Java реализован механизм массивов, исключающих необходимость использования указателей.
СБОР МУСОРА.
Одна из интереснейших особенностей языка программирования Java и среды выполнения приложений Java заключается в наличии специального процесса сборки мусора, предназначенного для удаления ненужных объектов из памяти. Эта система избавляет программиста от необходимости внимательно следить за использованием памяти, освобождая ненужные более области явным образом.
Создавая объекты в Java, вы можете руководствоваться принципом "создай и забудь", так как система сборки мусора позаботится об удалении ваших объектов. Объект будет удален из памяти, как только на него не останется ни одной ссылки из других объектов.
Приоритет процесса сборки мусора очень низкий, поэтому "уборка" среды выполнения приложений Java не отнимает ресурсы у самих приложений. Для создания объектов во время выполнения выделяется область динамической памяти. Язык Java рассчитан на то, что эту область обслуживает сборщик мусора, поскольку в языке нет средств для освобождения памяти. Как именно работает сборщик мусора, определяется реализацией Java-машины.
СИСТЕМА КОМАНД JAVA-МАШИНЫ.
Команда Java-машины состоит из однобайтного кода операции, за которым следуют операнды (если таковые имеются). Можно выделить следующие группы команд:
команды загрузки констант и переменных в стек операндов. Для каждого типа данных имеются свои команды загрузки. Например, команда с кодом операции dload и операндом, задающим смещение, загружает в стек из локальной переменной вещественное число двойной точности, а команда aload делает то же для ссылки на объект.
команды запоминания данных из стека в локальных переменных.
команды управления массивами. Например, команда newarray с операндом, задающим тип элементов, извлекает из стека требуемый размер массива, создает его и помещает в стек ссылку на массив. Отметим, что для создания массивов с элементами-объектами служит другая команда, anewarray. За счет подобной специализации достигается эффективность интерпретации Java-программ.
команды работы со стеком. К этой группе относятся команды, которые удаляют, дублируют, меняют местами верхние элементы стека операндов, а также выполняют другие, более сложные манипуляции со стеком.
арифметические команды. Операнды извлекаются из стека; туда же помещается результат.
логические команды (сдвиг, и, или, исключающее или).
команды преобразования к другому типу.
команды передачи управления. Например, в команде jsr (переход на подпрограмму) операндом служит относительный адрес перехода; адрес команды, следующей за jsr, помещается на вершину стека операндов. Имеются команды для реализации переключателей.
команды возврата из функции. Для возврата результатов разных типов используются команды с разными кодами операции. Кроме того, имеется команда breakpoint, которая останавливает нормальный ход выполнения и передает управление обработчику этого события.
команды манипулирования с полями объектов (установить/ прочитать обычное/статическое поле).
команды вызова методов. Их четыре. Команда invokevirtual вызывает (виртуальный) метод на основе анализа информации времени выполнения. Команда invokenonvirtual осуществляет вызов на основе информации времени компиляции - например, вызов метода родительского класса. Команда invokestatic вызывает статический метод класса. Наконец, команда invokeinterface вызывает метод, представленный интерфейсом. Выполнение всех перечисленных команд связано не только с передачей управления, но и с анализом разного рода таблиц.
команда возбуждения исключительной ситуации - athrow.
прочие объектные операции (создать объект, проверить тип объекта).
команды синхронизации (войти в критический интервал, выйти из него).
Отсюда видно, что не существует семантического разрыва между языком Java и Java-машиной. Это важно для компактности скомпилированных Java-программ и для обеспечения высокой скорости трансляции.
СВЯЗЬ JAVA С ОКРУЖЕНИЕМ: ОКОННЫЙ ИНСТРУМЕНТАРИЙ.
ОБЩИЕ ПОЛОЖЕНИЯ.
Одно из важных достоинств Java состоит в том, что это не только язык, но и стандартизованная объектно-ориентированная среда выполнения. Любопытно проследить, как в рамках Java решаются традиционные программистские проблемы. Мы остановимся на оконном графическом интерфейсе.
Вместе с различными приятными (главным образом для пользователя) свойствами, оконный интерфейс привносит и довольно неприятные (для разработчика) проблемы. Одна из них - это переносимость приложений между разными платформами. Переносимость является проблемой и без графического интерфейса, однако наличие такового делает ее многократно сложнее.
Дело в том, что каждая оконная среда - это сложный мир, со своими законами, набором строительных блоков и приемов программирования. Motif не похож на MS-Windows и оконную систему Macintosh. По-разному представляются примитивные элементы интерфейса, по-разному обрабатываются внешние события, по-разному происходит рисование на экране и т.д.
Вместе с тем, по своей сути оконная среда - просто идеальное поле деятельности для объектного программирования. Даже человеку, неискушенному в объектно-ориентированных методах проектирования, ясно, что такие вещи, как кнопки, текстовые поля, меню, вполне заслуживают названия объектов, как бы это слово ни понималось. Иначе говоря, вполне понятно, что такое "кнопка вообще", "список вообще" и т.д.
Все это дает основания надеяться, что с помощью объектно-ориентированного подхода можно получить по-настоящему высокоуровневую и переносимую оконную среду, основанную на абстрактных типах данных.
Данная особенность оконных сред проявилась, в частности, в появлении довольно большого количества различных классовых библиотек, "обертывающих" оригинальные оконные системы. В качестве примеров можно привести MFC, OWL, Zink и многие другие.
Вот и среди стандартных Java-библиотек присутствует AWT или Abstract Windowing Toolkit - абстрактный оконный инструментарий.
AWT является системой классов для поддержки программирования в оконной среде. Его "абстрактность" проявляется в том, что все, зависящее от конкретной платформы, хорошо локализовано и спрятано. В AWT реализованы такие простые и понятные вещи, как кнопки, меню, поля ввода; простые и понятные средства организации интерфейса - контейнеры, панели, менеджеры геометрии. Это хорошо видно на рис. 9.
Рис. 9. Основные элементы иерархии классов AWT.
Все зависимости от платформы содержатся в ветви, обозначенной как Peer.
Далее мы рассмотрим некоторые особенности AWT, не претендуя на полноту изложения. Наша цель - дать общее представление о технологии программирования графического оконного интерфейса в среде Java.
ИЗ ЧЕГО СТРОИТСЯ ГРАФИЧЕСКИЙ ИНТЕРФЕЙС (КОМПОНЕНТЫ И КОНТЕЙНЕРЫ).
Если посмотреть на любое оконное приложение, то легко увидеть, что интерфейсная часть состоит из объектов, объединенных в группы. В AWT объекты называются компонентами (на самом деле они все являются наследниками класса Component), а группы объектов реализованы с помощью так называемых контейнеров. Отметим, что любой контейнер - это тоже компонента, поэтому группы объектов могут быть вложены друг в друга. Как обычно, меню стоят особняком.
К числу примитивных компонент относятся:
Button
Checkbox
Label
List
ScrollBar
TextArea
TextField
Основные контейнеры:
Dialog
FileDialog
Frame
Panel
Window
Взаимодействие интерфейсных компонент с пользователем реализовано с помощью аппарата событий.
JAVA И БЕЗОПАСНОСТЬ.
Концепция загрузки объектов по сети прозрачным для пользователя образом столь же привлекательна, сколь и опасна. Если не предпринимать никаких мер и не накладывать никаких ограничений на возможности Java-аплетов, вход на любую Web-страницу может привести к непредсказуемым последствиям. К счастью, разработчики языка Java с самого начала уделяли самое пристальное внимание вопросам информационной безопасности.
Из языка удалены многие потенциально опасные возможности, такие как оператор goto или тип данных "указатель". Интерпретируемый характер выполнения позволяет не допустить выхода за границы массива, обращения по пустой ссылке и т.п.
Уделим основное внимание выполнению потенциально враждебных аплетов. Смежный вопрос - проверка подлинности аплетов, снабженных электронной подписью, видимо, будет решен в последующих версиях Java-систем.
Прежде всего, аплетам, загруженным по сети, запрещены чтения и запись файлов из локальной файловой системы, а также выполнение сетевых соединений со всеми хостами, кроме того, с которого был получен аплет. Кроме того, таким аплетам не разрешается запускать программы на клиентской системе (говоря языком ОС UNIX, для них недоступны системные вызовы fork и exec), им запрещено загружать новые библиотеки и вызывать программы, внешние по отношению к Java-машине.
На самом деле, перечисленные ограничения не являются частью спецификации Java-системы и могут выполняться с большей или меньшей аккуратностью. Так, в Netscape Navigator 2.0 чтение и запись локальных файлов действительно полностью запрещены. В то же время, среда разработки JDK 1.0 компании Sun Microsystems допускает задание списка каталогов, с которыми аплеты могут работать.
Более точно, вне разрешенного списка каталогов аплет не может:
проверять существование файлов;
читать/писать/переименовывать файлы;
создавать каталоги;
проверять атрибуты файла тип, время последней модификации, размер.
Чтобы в JDK сделать каталог доступным для аплета, следует поместить в файл ~/.hotjava/properties строки вида
acl.read=/home/welcome
acl.write=/tmp
Перед началом работы аплетов они проверяются верификатором байт-кодов. Верификатор убеждается, что загруженный аплет соответствует спецификациям, заданным при компиляции вызывающей программы, что не нарушен формат скомпилированного файла, что нет переполнения или исчерпания стека, нет некорректных преобразований типов, неправильных действий с регистрами и т.п. Все эти проверки верификатор осуществляет на основе анализа потоков данных. Особенно тщательно проверяются конструкции finally обработчиков исключительных ситуаций.
Следует отметить, что верный выбор баланса между возможностями загружаемых аплетов и безопасностью клиентской системы является очень тонким вопросом. Ряд компаний, например, Argus System Group, предлагают реализовать на клиентской системе усиленные меры безопасности, чтобы успешно отражать угрозы со стороны враждебных аплетов без ограничения свободы действий для "благонадежных" программ. К сожалению, предлагаемые решения зависят от операционной платформы, что противоречит требованию абсолютной переносимости Java-программ. Можно предположить, что информационная безопасность еще долгое время будет оставаться одним из самых сложным и спорных вопросов, касающихся проекта Java.
Вывод.
Данная выпускная работа посвящена языку Java. Подведем итоги, в которых покажем необходимость изучения языка Java.
Изучая Java, вы будете приятно удивлены тем, что его синтаксис близок к синтаксису языка C++. Унаследовав самое лучшее от языка программирования C++, язык Java при этом избавился от некоторых недостатков C++, в результате чего на нем стало проще программировать. В этом языке нет, например, указателей, которые сложны в использовании и потенциально могут послужить причиной доступа программы к не принадлежащей ей области памяти. Нет множественного наследования и шаблонов, хотя функциональные возможности языка Java от этого не пострадали. Если вы умеете программировать на C++, для вас не составит особого труда изучить язык Java.
Почему вам нужно изучать новый язык программирования Java?
Если ответить на этот вопрос кратко, то потому, что он специально ориентирован на самые передовые технологии, связанные с сетью Internet. Растущая популярность Internet и, в особенности, серверов Web, создает для программистов новые возможности для реализации своих способностей.
Огромное преимущество Java заключается в том, что на этом языке можно создавать приложения, способные работать на различных платформах. Однако следует отметить, что создание приложений, действительно работающих на разных платформах - непростая задача. К сожалению, дело не ограничивается необходимостью перекомпиляции исходного текста программы для работы в другой среде. Много проблем возникает с несовместимостью программных интерфейсов различных операционных систем и графических оболочек, реализующих пользовательский интерфейс.
Первоначально средства разработки приложений и аплетов Java были созданы фирмой Sun Microsystems и до сих пор они пользуются популярностью. Для тех, кто привык пользоваться визуальными средствами разработки, доступны два других инструмента, созданных в Sun Microsystems. Это Java WorkShop 2.0 и Java Studio 1.0. Интегрированная система разработки приложений Java WorkShop 2.0 содержит традиционные и визуальные средства программирования, отладчик, обширную справочную систему по классам и языку Java. С помощью Java WorkShop 2.0 вы можете создавать автономные приложения Java, аплеты, компоненты JavaBeans и собственные библиотеки классов.
Что же касается Java Studio 1.0, то эта система позволяет проектировать приложения вообще без программирования. Разработчик собирает приложения из готовых компонент, устанавливая между ними каналы передачи сообщений. Таким образом, определяется логика работы приложения.
Для проверки работы аплетов следует установить браузер, способный работать с аплетами Java. Такая возможность есть во всех современных браузерах, можно выбрать любой из них. Лучше всего проверять работу создаваемых аплетов в различных браузерах. Это позволит обнаружить и решить проблемы несовместимости, прежде чем с ними столкнется пользователь.
Для запуска аплетов не нужно обязательно подключаться к Internet – можно встраивать аплеты в документы HTML, расположенные на локальном диске компьютера и просматривать эти документы браузером просто как локальные файлы.
Автономные приложения Java работают под управлением специального интерпретатора (виртуальной машины Java), поэтому для их отладки также не потребуется сеть Internet.
Однако есть одно важное обстоятельство - аплеты, взаимодействующие с расширениями сервера Web, должны быть загружены именно с этого сервера. В противном случае их работа будет заблокирована по соображениям безопасности.
Программы, составленные на языке программирования Java, можно разделить по своему назначению на две большие группы. К первой группе относятся приложения Java. Вторая группа - это аплеты.
Приложения, относящиеся к первой группе - это обычные автономные программы. Так как они не содержат машинного кода и работают под управлением специального интерпретатора, их производительность заметно ниже, чем у обычных программ. Аплеты Java встраиваются в документы HTML, хранящиеся на сервере Web. С помощью аплетов можно сделать страницы сервера Web динамичными и интерактивными.
Для повышения производительности приложений Java в современных браузерах используется компиляция Just-In-Time compilation. При первой загрузке аплета его код транслируется в обычную исполнимую программу, которая сохраняется на диске и запускается. В результате общая скорость выполнения аплета Java увеличивается в несколько раз.
Список литературы.
Хэлсоп Б., Бадник Л. HTML. –Санкт-Петербург, 1998. –300с.
Мир ПК // Инетернет для всех. –1997. -№3. -С.58 - 68.
Чип // Java – миф или реальность. –1998. -№2. –С. 27-34
Мафтик С.М. Механизмы защиты в сетях ЭВМ. - М.: Мир, 1993. – 256 с.
Гаффин А. Руководство по глобальной компьютерной сети Internet. -Network World, 1998. –500 с.
Капор М. Ява для всех. - Санкт-Петербург, 1997. –200 с.
Мильвидский А. М. Введение в Java. –1998. –250 с.