Словарь Java-терминов

Java >

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

100% Pure Java
Под термином "100% Pure Java" понимают Java-программу, которая опирается только на специфицированное поведение Java-платформы, не использует платформно-зависимых (native) методов и не зависит ни от каких программных интерфейсов, кроме Java core API. Программа сертификации служит для того, чтобы определить, является ли данное приложение или апплет 100% Pure Java или нет.

A

Abstract Window Toolkit - AWT
Стандартный пакет графических компонент, реализованных с использованием специфических платформенных методов. Данные компоненты поддерживают лишь то подмножество функциональных возможностей, которое присуще всем платформам.

В значительной степени вытеснен набором компонент Project Swing (см. Swing-компоненты).

abstract
Ключевое слово языка программирования Java, используемое в определении класса для указания на невозможность создания его экземпляров, но при этом доступного для наследования другими классами. Абстрактный класс может содержать нереализованные (абстрактные) методы, которые должны быть реализованы в его подклассах.

abstract class (абстрактный класс)
Класс, который содержит один или более абстрактных методов, вследствие чего нельзя создавать экземпляры данного класса. Абстрактные классы определены таким образом, чтобы другие классы могли расширять и конкретизировать их, реализуя абстрактные методы.

abstract method (абстрактный метод)
Метод, не имеющий реализации.

access control (контроль доступа)
Технические средства, посредством которых ограничиваются множества пользователей или программ, взаимодействующих с ресурсами, с целью повышения целостности, конфиденциальности и доступности.

ACID - Atomicity, Consistency, Isolation and Durability (АЦИН)
Акроним четырех свойств, обеспечиваемых транзакциями: атомарность, целостность, изоляция и надежность.

activation (активация)
Процесс передачи корпоративных компонент (enterprise beans) из вторичного устройства хранения данных в память.

actual parameter list (список фактических параметров)
Аргументы, определенные в вызове метода (см. список формальных параметров).

alpha value (альфа-фактор)
Значение, указывающее яркость (или интенсивность) пикселя.

API - Application Programming Interface (интерфейс прикладного программирования)
Спецификация, предназначенная для пользователей и описывающая методы доступа к свойствам и состоянию объектов и классов.

applet (апплет)
Компонент, который обычно исполняется в Web-браузере или в любой другой программе просмотра апплетов.

applet container (контейнер апплетов)
Контейнер, включающий в себя поддержку модели программирования апплетов.

appliances (устройства)
Сетевые устройства, такие как принтеры, терминалы с поддержкой технологии Java и клиенты, управляемые посредством использования Java Management API (JMAPI).

application assembler (компоновщик приложения)
Человек, объединяющий компоненты и модули в большие модули разработки.

application client (клиентское приложение)
Клиентская программа первого уровня, исполняемая на собственной виртуальной Java-машине.

application client container (контейнер клиентского приложения)
Контейнер, поддерживающий клиентские приложения и обеспечивающий интегрированное представление API платформы J2EE.

application client module (модуль клиентского приложения)
Программный модуль, состоящий из одного или более классов и описания клиентского приложения.

Application Component Provider (поставщик программных компонент)
Поставщик, который предоставляет классы Java, реализующие методы компонентов, описания JSP-страниц и необходимые дескрипторы.

Application Programming Model - APM (модель программирования приложения)
Модель прикладного программирования, которая определяет, как использовать и объединять возможности платформы J2EE для создания прикладных решений в предметной области предприятия.

argument (аргумент)
Элемент данных, указанный в вызове метода. Аргумент может быть константой, переменной или выражением.

array (массив)
Совокупность элементов данных одного типа, в которой позиция каждого элемента однозначно определена целым числом (индексом массива).

Американский Стандартный Код Обмена Информацией (American standard code for information interchange - ASCII)
Стандартно, на один символ отводится 7 бит. См. также Уникод.

atomic (атомарный)
Операция, выполняемая как единый неделимый акт.

authentication (аутентификация)
Процесс, посредством которого один объект показывает другому, что он действует от имени определенной идентификационной записи. Платформа J2EE нуждается в трех видах аутентификации: обычной (basic), связанной с формой (form-based) и взаимной (mutual).

authorization (авторизация)
См. управление доступом.

authorization constraint (ограничение авторизации)
Набор ролевых имен, предназначенных для защиты и разрешающих доступ к Web-ресурсам.

B

basic authentication (базовая (открытая) аутентификация)
Метод проверки Web-сервером имени пользователя и пароля, полученных при помощи механизма аутентификации, встроенного в Web-клиент.

bean (bean-компонент)
Программный компонент многократного использования. Bean-компоненты могут быть объединены для создания приложения.

механизм сохранения, управляемый bean-компонентом (bean-managed persistence)
Механизм, при котором передача данных между переменными экземпляров bean-компонента и основным администратором ресурсов управляется bean-компонентом.

транзакция, управляемая bean-компонентом (bean-managed transaction)
Корпоративный компонент (enterprise bean) определяет границы транзакции.

binary operator (бинарный оператор)
Знак операции, имеющий два аргумента.

bit (бит)
Минимальная единица информации в компьютере. Может принимать значения 0 или 1.

bitwise operator (побитовый оператор)
Знак операции, воздействующий на операнды, как на набор битов (0 и 1). Например, бинарные логические операции (&, |, ^), бинарные операции сдвига (<<, >>, >>>) и унарная операция дополнения (~).

block (блок)
Любой код на языке программирования Java, заключенный между двумя фигурными скобками. Например, {x = 1;}.

boolean (булевский)
Относится к выражению или переменной, которые могут принимать только два значения: true ("истина") и false ("ложь"). В языке программирования Java существует тип boolean, а также литеральные константы true и false.

bounding box (ограничительная область)
Прямоугольник наименьшего размера, содержащий указанную геометрическую фигуру. Для растровых объектов включает все заданные пиксели.

break
Ключевое слово языка программирования Java. Оператор break передаёт управление строке, следующей за текущей структурой. Если за break следует метка, то программа продолжает исполнение, начиная с "помеченного" оператора.

business logic (бизнес-логика)
Код, реализующий функциональность приложения. В модели Enterprise Java Beans эта логика реализуется при помощи методов корпоративного компонента (enterprise bean).

business-method (бизнес-метод)
Метод корпоративного компонента (enterprise bean), реализующий бизнес-логику или правила приложения.

byte (байт)
Последовательность из восьми битов. В языке программирования Java определен соответствующий тип byte.

bytecode (байт-код)
Машинно-независимый код, генерируемый Java-компилятором и исполняемый Java-интерпретатором.

С

callback methods (методы обратной связи)
Метод компонента, вызываемый контейнером для уведомления компонента о важных событиях во время его жизненного цикла.

caller (вызывающий оператор)
См. администратор вызывающего оператора

caller principal (администратор вызывающего оператора)
Администратор, который идентифицирует объект, вызывающий метод корпоративного компонента (enterprise bean).

case
Ключевое слово языка программирования Java (оператор switch), которое определяет набор инструкций, исполняющихся в случае, если значение переключающего выражения совпадает со значением константы (разметки выбирающего предложения), указанной в конструкции case.

casting (преобразование типа)
Явное преобразование одного типа данных в другой.

catch
Ключевое слово языка программирования Java, используемое для объявления блока инструкций, которые должны быть выполнены в случае исключительной ситуации или ошибки выполнения, возникающей в предшествующем блоке try.

char
Ключевое слово языка программирования Java, используемое для объявления переменной символьного типа.

class (класс)
Тип в языке программирования Java, определяющий реализацию особого вида объекта. Описание класса определяет экземпляр класса, его переменные и методы. Так же определяются интерфейсы и суперклассы. По умолчанию суперклассом любого класса является Object.

class method (метод класса {типа})
Метод, который вызывается безотносительно ссылки на конкретный объект. Методы класса влияют на класс в целом, а не на конкретный его экземпляр.

Также носит название статического метода. См. также метод экземпляра.

classpath (путь к классам)
Переменная среды окружения, которая сообщает виртуальной машине Java и приложениям Java (например, утилитам, расположенным в директории JDK 1.1.X\bin), где находятся библиотеки классов, включая пользовательские библиотеки.

Свойство виртуальной машины (JVM), которое может быть задано с помощью переменной окружения, либо другими способами, например, с помощью опций JVM.

class variable (переменная класса {типа})
Переменная, относящаяся к некоторому классу в целом, а не к отдельным экземплярам класса. Переменные класса являются элементами определения класса.

Также носит название статического поля. См. также переменная экземпляра.

client (клиент)
В модели соединения "клиент-сервер" клиент - это процесс, который удаленно обращается к ресурсам вычислительного сервера.

codebase (адрес основного кода)
При работе с атрибутом code в тэге APPLET указывает полный путь к файлу главного класса апплета: code определяет имя файла, а codebase - URL директории, содержащей файл.

comment (комментарий)
Поясняющий текст в программе, который игнорируется компилятором. В приложениях Java комментарии выделяются символами // или /*…*/.

commit (фиксация {транзакции})
Момент транзакции, когда все изменения, проведенные в процессе транзакции, фиксируются в базе данных.

compilation unit (единица компиляции)
Минимальная единица исходного кода, которая может быть откомпилирована. В текущей реализации Java единица компиляции - это последовательность определений интерфейсов и классов, которой могут предшествовать объявление пакета и объявления импорта.

compiler (компилятор)
Программа, транслирующая исходный код приложения в код, исполняемый компьютером. Java-компилятор транслирует исходный код, написанный на языке Java, в машинно-независимый код (байт-код) для виртуальной машины Java. См. также интерпретатор.

component (компонент)
Программный модуль, поддерживаемый контейнером. Компоненты конфигурируемы на стадии разработки. Платформа J2EE определяет четыре вида компонент: корпоративные компоненты (enterprise beans), Web-компоненты, апплеты и клиентские приложения.

component contract (контракт компонента)
Набор условий, регулирующих отношения между компонентом и его контейнером. Контракт включает: управление жизненным циклом компонента, контекстный интерфейс, используемый образцом компоненты для получения информации о контейнере или использования возможностей контейнера, и списка функциональных возможностей, которые должен поддерживать каждый контейнер для данной компоненты.

component environment (окружение компонента)
Набор требований, определяемых Поставщиком Программных Компонент (Application Component Provider), которые должны быть доступны компоненту J2EE. Записи окружения декларативно определены в описании компонента. Каждый компонент указывает и получает доступ к значениям конфигурации компонента, используя контекст java:comp/env JNDI. Эти значения могут быть объектами, от которых зависит компонент, такими как JDBC DataSource или простыми значениями, такими как налоговая ставка.

compositing (компоновка)
Процесс наложения одного изображения на другое, с целью получения единого изображения.

connection (соединение)
См. менеджер соединений.

connection factory (мастер соединения)
См. менеджер ресурсов мастера соединения.

connector (коннектор)
Стандартный механизм расширения контейнеров для обеспечения взаимодействия с управленческими информационными системами (Executive Information Systems - EISs). Коннектор специфичен для каждой EIS и состоит из адаптера ресурсов и средств разработки приложений для взаимодействия с EIS. Адаптер ресурсов подключен к контейнеру посредством контрактов системного уровня, определенных в архитектуре коннектора.

connector architecture (архитектура коннектора)
Архитектура, предназначенная для интеграции серверов J2EE с управленческими информационными системами (Executive Information Systems - EISs). Архитектура состоит из двух частей: адаптер ресурсов производителя EIS и сервер J2EE, поддерживающий этот адаптер. Данная архитектура определяет набор контрактов, которые должны поддерживаться адаптером ресурсов для подключения к J2EE-серверу. Например, транзакции, обеспечение безопасности, управление ресурсами.

constructor (конструктор)
Метод особого рода, создающий объект и инициализирующий его поля. В языке программирования Java имя конструктора совпадает с именем класса. Конструкторы вызываются системой при создании экземпляра объекта (исполнении конструкции new).

const
Зарезервированное ключевое слово языка Java. Однако, не используется текущими версиями Java.

container (контейнер)
Сущность, обеспечивающая управление, безопасность, разработку и сервисы выполнения компонент. Кроме того, каждый тип контейнера (EJB, Web, JSP, сервлет, апплет или приложение-клиент) также предоставляет свои специфические сервисы.

container-managed persistence (персистенция {сохраняемость}, управляемая контейнером)
Механизм, при котором передача данных между экземпляром корпоративной компоненты и менеджером расположенных ниже ресурсов управляется контейнером корпоративной компоненты (enterprise bean).

container-managed transaction (транзакция, управляемая контейнером)
Транзакция, границы которой определяются EJB-контейнером. Экземпляр корпоративной компоненты (enterprise bean) должен использовать транзакции, управляемые контейнерами.

context attribute (контекстный атрибут)
Объект, встроенный в контекст, ассоциированный с сервлетом.

continue
Ключевое слово языка программирования Java, которое обозначает оператор, завершающий текущую итерацию цикла и, если условие повторения выполняется, начинающий исполнение следующей. Если за данным ключевым словом следует метка, continue возобновляет исполнение, начиная с помеченного оператора (то есть начинается следующая итерация цикла, помеченного данной меткой).

conversational state (диалоговый режим)
Значения полей сессии bean-компонента плюс транзитивное замыкание объектов, доступных из полей bean-компонента. Транзитивное замыкание bean-компонента определяется в терминах протокола сериализации языка Java, которые сохранены посредством сериализации экземпляра bean-компонента.

Common Object Request Broker Architecture - CORBA
Технология построения распределенных объектных приложений, специфицируемая группой по развитию стандартов объектного программирования (Object Management Group - OMG).

core class (базовый класс)
Публичный класс (или интерфейс), являющийся стандартным членом Java Platform. Обязательным свойством таких классов является их доступность в любой операционной системе, поддерживающей среду Java. Программой, "полностью" написанной на языке Java, называется программа, использующая только такие классы, и, следовательно, обладающая свойством независимости от платформы. См. также 100% Pure Java.

core packages (базовые пакеты)
Необходимый набор программных интерфейсов приложений (Application Programming Interfaces - APIs) платформы Java, который поддерживается в любой реализации.

create method (метод create)
Метод, определенный в "домашнем" интерфейсе и вызываемый клиентом, для создания корпоративной компоненты (enterprise bean).

credentials (полномочия)
Учетная запись с параметрами доступа пользователя, сформированными после его успешной аутентификации.

critical section (критическая секция)
Фрагмент программы, в котором поток выполняет действия над общим ресурсом, доступ к которому должен быть монопольным.

Compatibility Test Suite - CTS (пакет проверки совместимости)
Набор программ, предназначенных для проверки соответствия продуктов J2EE спецификации платформы J2EE.

D

declaration (объявление)
Выражение, связывающее идентификатор с атрибутами (типом). При необходимости осуществляется выделение памяти (для данных) или выполнение (для методов). См. также описание.

default
Ключевое слово языка программирования Java, при необходимости используемое после всех условий case в блоке switch. Если ни одно из проверяемых значений не совпадает со значением оператора switch, то выполняются инструкции, следующие после ключевого слова default.

definition (описание)
Объявление, осуществляющее резервирование памяти (для данных) или выполнение (для методов). См. также объявление.

delegation (делегирование)
Передача (делегирование) функций - способность объекта или потока внутри объекта выполнять под именем клиента запросы к другим удаленным объектам.

deployer (администратор размещения)
Человек, устанавливающий модули и приложения J2EE в операционной системе.

deployment (размещение)
Процесс установки программного обеспечения в операционную среду.

deployment descriptor (дескриптор размещения)
XML-файл, поставляемый с каждым модулем и приложением и описывающий процесс их установки. Дескриптор размещения управляет инструментами для установки модуля или приложения с какими-либо специфичными опциями контейнера, а также описывает особые требования, предъявляемые к конфигурации.

deprecation (антирекомендация)
Относится к классам, интерфейсам, конструкторам, методам или полям, которые рекомендуется больше не использовать, и которые могут быть исключены из последующих версий.

derived from ("является потомком")
Класс X "является потомком" класса Y, если класс X расширяет (наследует) класс Y. См. также подкласс, суперкласс.

distributed (распределенный)
Работающий более чем в одном адресном пространстве.

distributed application (распределенное приложение)
Приложение, которое составлено из различных компонент, выполняющихся в различных средах, обычно, на разных платформах, соединенных посредством сети. Стандартные распределенные приложения: двухзвенное (клиент/сервер), трехзвенное (клиент/промежуточное программное обеспечение/сервер), n-звенное (клиент/множественное промежуточное программное обеспечение/сервер).

do
Ключевое слово языка программирования Java, используемое для объявления цикла, повторяющего блок инструкций. Условие выхода из цикла определяется ключевым словом while в конце итерации.

Document Object Model - DOM (объектная модель документа)
Дерево объектов и интерфейсы для реализации обхода вершин дерева и написания его XML-версии согласно спецификации W3C.

double
Ключевое слово языка программирования Java, используемое для определения переменной типа double.

double precision (двойная точность)
Согласно спецификации языка программирования Java, число с плавающей точкой, занимающее 64 бита данных. См. также одинарная точность.

Document Type Definition - DTD (определение типа документа)
Описание структуры и свойств XML-файлов.

E

EJB-container (EJB-контейнер)
Контейнер, содержащий корпоративные компоненты (EJB).

EJB Container Provider (поставщик EJB-контейнера)
Производитель, который предоставляет EJB-контейнер.

EJB-context (EJB-контекст)
Объект, позволяющий корпоративному компоненту (enterprise bean) запускать сервисы контейнера и получать информацию о программе, вызвавшей клиентский метод.

EJB home object ("домашний" объект EJB)
Объект, обеспечивающий жизненный цикл операций (создания, удаления, поиска) для корпоративного компонента (enterprise bean). Класс для "домашнего" объекта EJB порожден инструментами разработки контейнера. "Домашний" объект EJB реализует собственный интерфейс корпоративного компонента (enterprise bean). Клиент ссылается на "домашний" объект EJB, чтобы выполнить операции жизненного цикла EJB-объекта. Для определения местонахождения EJB home object клиент использует JNDI интерфейс.

EJB-.jar file (EJB .jar файл)
Архив JAR, который содержит EJB-модуль.

EJB module (EJB модуль)
Программный модуль, который состоит из одного или более корпоративных компонентов (enterprise beans) и дескриптора установки EJB.

EJB object (EJB объект)
Объект, чей класс реализуется удаленным интерфейсом корпоративного компонента (enterprise bean). Клиент никогда не ссылается непосредственно на экземпляр корпоративного компонента, а только на объект EJB. Класс для объекта EJB порожден инструментами разработки, входящими в состав контейнера.

EJB-server (EJB-сервер)
Программное обеспечение, предоставляющее службы EJB-контейнеру. Например, EJB-контейнер обычно зависит от менеджера транзакций, который является частью EJB-сервера, предназначенной для двухфазного завершения распределенных транзакций параллельно со всеми участвующими в ней менеджерами ресурсов. Архитектура J2EE предполагает, что EJB-сервер, содержащий EJB-контейнер, поставляется тем же производителем, поэтому не существует соглашения между двумя этими сущностями. EJB-сервер может содержать один и более контейнеров EJB.

EJB Server Provider (поставщик EJB-сервера)
Производитель, который поставляет EJB-сервер.

EIS resource (ресурс управленческой информационной системы {ресурс УИС})
Сущность, предоставляющая функциональные возможности УИС клиентам системы. Например, запись или множество записей в системе базы данных, бизнес-объект в ERP-системе (системе, предназначенная для планирования и управления ресурсами предприятий), программа транзакции в системе обработки транзакций.

else
Ключевое слово языка программирования Java, используемое для выполнения блока инструкций в том случае, если проверка условия в операторе if дала отрицательный результат (false).

Embedded Java technology (технология EmbeddedJava)
Технология, которая впервые появилась в рамках Java 2 Platform. Распространение этой технологии ограничено лицензионным соглашением, которое позволяет владельцу лицензии использовать определенные Java-технологии для создания и внедрения встроенных приложений.

encapsulation (инкапсуляция)
Локализация (упрятывание) части данных в пределах класса. Поскольку объекты инкапсулируют данные и реализацию, пользователь может рассматривать объект как черный ящик, предоставляющий услуги. Переменные и методы экземпляров класса могут добавляться, удаляться или изменяться, но до тех пор, пока услуги, предоставляемые объектом, не изменяются, нет необходимости переписывать код, использующий данный объект. См. также переменная экземпляра класса и метод экземпляра класса.

enterprise bean (корпоративный компонент)
Компонент, реализующий бизнес-задачу или бизнес-объект, либо сущность или сессионный компонент.

Enterprise Information System - EIS (управленческая информационная система - УИС)
Приложения, которые содержат существующую систему управления информацией всей компании. Эти приложения обеспечивают информационную инфраструктуру предприятия. УИС предлагает определенный набор услуг своим клиентам. Эти услуги представлены клиентам как локальные и/или удаленные интерфейсы. Примеры УИС: ERP-система (система, предназначенная для планирования и управления ресурсами предприятий), универсальная система обработки транзакций, существующая система баз данных.

Enterprise Bean Provider (поставщик корпоративных компонент)
Прикладной программист, разрабатывающий классы корпоративных компонентов (enterprise beans), удаленные и локальные интерфейсы, файлы дескрипторов установки и упаковывает их в EJB-.jar файл.

Enterprise JavaBeans - EJB
Архитектура, предназначенная для развития и установки объектно-ориентированных, распределенных, корпоративных приложений. Приложения, написанные с использованием архитектуры Enterprise JavaBeans, являются масштабируемыми, многопользовательскими и безопасными.

entity bean (компонент управления данными)
Корпоративный компонент (enterprise bean), который отображает постоянные данные, хранящиеся в базе данных. Сущность идентифицируется первичным ключом. Если контейнер, которому принадлежит сущность, разрушается, сущность, ее первичный ключ и все удаленные ссылки сохраняются.

ebXML
ebXML основан на стандарте XML (Extensive Markup Language) и предназначен для поставки модульного набора спецификаций, позволяющего предприятиям различного масштаба и географического положения вести дела посредством Internet. ebXML снабжает компании и организации стандартным методом обмена деловой информацией, ведения торговых отношений, передачи данных, а также определения и регистрации бизнес процессов.

exception (исключительная ситуация)
Ситуация, возникающая во время работы программы вследствие неудачного выполнения операции, или запрограммированная с использованием оператора throw. Если в программе не предусмотрена реакция на возникшую ситуацию, дальнейшее исполнение программы невозможно. Язык программирования Java поддерживает обработку исключительных ситуаций при помощи ключевых слов try, catch и throw. См. также обработчик исключительных ситуаций.

exception handler (обработчик исключительных ситуаций)
Блок кода, реагирующий на определенный тип исключительных ситуаций. Если исключительная ситуация произошла вследствие ошибки, после которой программа может возобновить работу, то программа продолжает выполнение после обработчика исключительных ситуаций.

executable context (исполняемый код)
Программа, которая выполняется из HTML-файла. См. также апплет.

extends ("расширяет")
Класс X может "расширять" класс Y с целью добавления функциональности (при помощи добавления полей и методов классу Y или переопределения методов класса Y). В таком случае говорят, что класс X является подклассом класса Y. Один интерфейс "расширяет" другой при помощи добавления методов. См. также "произошел из".

F

finder method (метод поиска)
Метод, определенный в "домашнем" интерфейсе и вызываемый клиентом для нахождения сущности.

First Customer Ship - FCS (первая поставка пользователям)
Дата выпуска/передачи продукта пользователю.

field (поле)
Элемент класса. Пока не определено обратное, поле не является статическим.

final - терминальный
Ключевое слово языка программирования Java. Объявление класса с модификатором final означает, что класс нельзя расширить или наследовать. Final-методы не могут переопределяться, final-переменные не могут изменять свое начальное значение.

finally
Ключевое слово языка программирования Java, задающее блок операций, которые будут выполнены независимо от того, произошла исключительная ситуация или ошибка в блоке, определенном с ключевым словом try, или нет.

float
Ключевое слово языка программирования Java, используемое для определения числа с плавающей точкой.

for
Ключевое слово языка программирования Java, используемое для объявления цикла, повторяющего блок инструкций. Программист определяет выполняемые операции, условия выхода из цикла, а также некоторые начальные действия перед началом первой итерации (инициализацию служебных переменных и пр.).

form-based authentication (аутентификация, связанная с формой)
Аутентификация, при которой Web-сервер выдает специализированную форму для входа в систему.

File Transfer Protocol - FTP (FTP - протокол)
Internet-протокол, основанный на TCP\IP. Предназначен для передачи файлов между хост-компьютерами. См. также TCP\IP.

formal parameter list (список формальных параметров)
Параметры, заданные в описании метода. См. также список фактических параметров.

G

garbage collection ("сборка мусора")
Автоматическое обнаружение и освобождение памяти, которая больше не используется. Система управления и слежения за правильностью выполнения программы (Java runtime system) выполняет "сборку мусора" таким образом, чтобы программисту не требовалось напрямую вызывать методы освобождения памяти. При необходимости программист может запустить сборщик мусора явно, путем вызова специального метода. В этом случае сборка мусора будет выполняться синхронно.

goto
Зарезервированное слово языка программирования Java. Однако, в текущих версиях языка не используется.

group (группа)
Совокупность пользователей в пределах данного домена политики безопасности.

Graphical User Interface - GUI (графический интерфейс пользователя)
Графический интерфейс, предназначенный для удобства использования некоторых программ.

H

handle (манипулятор)
Объект, используемый для уникальной идентификации корпоративного компонента (enterprise bean). Клиент может сериализовать манипулятор, а затем десериализовать его для получения ссылки на корпоративный компонент (enterprise bean).

hexadecimal (шестнадцатеричный) Система счисления с основанием 16. Знаки 0-9 и a-f представляют цифры от 0 до 15. В программе, написанной на языке Java, шестнадцатеричные числа должны начинаться с символов 0x. См. также восьмеричный.

hierarchy (иерархия)
Классификация соотношений, в которой каждый элемент, кроме верхнего (называемого корнем), является специализированным видом элемента, расположенного над ним. Каждый элемент может иметь один или несколько элементов, находящихся ниже него в иерархии. В иерархии классов Java, образуемой при наследовании, корнем является класс Object.

home interface ("домашний" интерфейс)
Один из двух интерфейсов для корпоративного компонента (enterprise bean). "Домашний" интерфейс может определять несколько методов для создания и удаления корпоративного компонента (enterprise bean). Для сессионных компонентов (session beans) "домашний" интерфейс определяет методы создания и удаления, тогда как для сущностей (entity beans) - методы создания, нахождения и удаления.

home handle ("домашний" манипулятор)
Объект, используемый для получения ссылки на "домашний" интерфейс. "Домашний" манипулятор может быть сериализован и записан в ПЗУ, а также десериализован для получения ссылки.

HotJava Browser (Браузер HotJava)
Легко настраиваемый Web-браузер, разработанный компанией Sun Microsystems и написанный на языке программирования Java.

HyperText Markup Language - HTML (язык разметки гипертекста)
Файловый формат для гипертекстовых страниц в Internet, основанный на SGML. Очень прост и разрешает внедрение изображений, звуков, видео, полей форм, а также простое форматирование текста. Ссылки на другие объекты внедряются с помощью URL.

HyperText Transfer Protocol - HTTP (протокол передачи гипертекстовых файлов)
Internet-протокол, основанный на TCP/IP и предназначенный для доступа к гипертекстовым объектам с удаленного компьютера. См. также TCP/IP.

HyperText Transmission Protocol, Secure - HTTPS (протокол защищенной передачи гипертекстов)
HTTP в совокупности с SSL (Secure Sockets Layer) - протоколом защищенных сокетов.

I

Interface Definition Language - IDL (язык описания интерфейсов)
Интерфейсы прикладного программирования (APIs), написанные на языке Java, которые обеспечивают функциональную совместимость на основе стандартов и способность взаимодействия с CORBA (Common Object Request Broker Architecture).

identifier (идентификатор)
Имя элемента (переменной, класса, метода и проч.) программы, написанной на языке Java.

Internet InterORB Protocol - IIOP
Протокол, определяющий передачу сообщений между сетевыми объектами по протоколам TCP/IP и используемый для коммуникаций между брокерами объектных запросов CORBA.

if
Ключевое слово языка программирования Java, предназначенное для проверки условия и выполнения блока инструкций, если проверка дала положительный результат (true).

impersonation (заимствование прав)
Процесс, при котором одна сущность принимает идентичность и привилегии другой сущности без ее уведомления о том, что произошло делегирование. Заимствование прав - это случай простого делегирования.

implements
Ключевое слово языка программирования Java, включаемое при необходимости в объявление класса, для определения интерфейсов, которые реализует данный класс.

import
Ключевое слово языка программирования Java, определяющее классы или целые пакеты, на которые может ссылаться программа, без включения названий пакетов в ссылку.

inheritance (наследование)
Концепция классов, автоматически включающих все переменные и методы, определенные в супертипе. См. также суперкласс, подкласс.

initialization parameter (параметр инициализации)
Параметр, который инициализирует контекст, связанный с сервлетом.

instance (экземпляр)
Объект класса. В программах, написанных на языке Java, экземпляр класса создается при помощи оператора new, за которым следует имя класса-типа.

instance method (метод экземпляра)
Любой метод, который вызван от имени экземпляра класса. Также называется просто метод. См. метод класса.

instance variable (переменная экземпляра)
Любой элемент данных, связанный с объектом. Каждый экземпляр класса имеет собственную копию переменной, определенной в классе. Также носит название поля. См. переменная класса.

instanceof
Ключевое слово языка программирования Java, имеющее два аргумента и проверяющее, является ли тип первого аргумента преобразуемым к типу второго аргумента.

int
Ключевое слово языка программирования Java, используемое для определения переменной целого типа (integer).

interface
Ключевое слово языка программирования Java, используемое для определения набора методов и постоянных значений (класса специального вида). Интерфейс в дальнейшем может реализовываться классами, которые определяют этот интерфейс с ключевым словом implements.

Internet (Интернет, международная компьютерная сеть)
Огромная сеть, состоящая из миллионов компьютеров многих организаций и стран всего мира. Физически сеть Internet составлена из большого количества сетей, причем данные передаются при помощи единого набора протоколов.

Internet Protocol - IP (протокол сети Интернет)
Основной протокол Internet. Осуществляет ненадежную доставку индивидуальных пакетов от одного компьютера другому. Не дает никаких гарантий о том, будет ли доставлен пакет, сколько времени займет доставка, придут ли групповые пакеты в том порядке, в котором они были посланы. Протоколы, надстроенные над IP, добавляют понятия связности и надежности. См. также TCP/IP.

interpreter (интерпретатор)
Программа, которая поочередно декодирует и исполняет каждую инструкцию кода. Интерпретатор Java декодирует и выполняет код для виртуальной машины Java*. См. также компилятор, система поддержки и выполнения программ.

Independent Software Vendor - ISV (независимый поставщик ПО)
Фирма, разрабатывающая программное обеспечение для платформы, созданной другой организацией.

J

J2EE application (приложение J2EE)
Любой составной модуль, поддерживающий функциональность J2EE. Это может быть один модуль или группа модулей, упакованных в .war-файл, содержащий дескриптор размещения J2EE-приложения. Приложения J2EE обычно проектируются так, что они распределены по нескольким вычислительным уровням.

J2EE product (продукт J2EE)
Продукт разработки, соответствующий спецификации платформы J2EE.

J2EE Product Provider (поставщик продуктов J2EE)
Производитель, поставляющий продукты J2EE.

J2EE server (сервер J2EE)
Исполняемая часть продукта J2EE. Сервер J2EE обеспечивает Web и/или EJB-контейнеры.

JAIN
См. Java APIs for Integrated Networks.

Java ARchive files (.jar) (JAR-файлы)
Файловый формат, используемый для группирования нескольких файлов в один.

JAR file format (файловый формат JAR)
Платформно-независимый файловый формат, соединяющий несколько файлов в один. Составные апплеты, написанные на языке Java, и необходимые для них компоненты (.class-файлы, изображения, звуковые и другие файлы) могут быть упакованы в JAR-файл и затем загружены в браузер за одну HTTP-транзакцию. Данный формат также поддерживает сжатие файлов и цифровые подписи.

Java
Торговая марка компании Sun для ряда технологий по созданию и безопасной работе программного обеспечения как в автономных, так и в сетевых средах.

Java Application Environment - JAE
Версия исходного кода программного обеспечения Java Development Kit (JDK).

Java APIs for Integrated Networks - JAIN
Дает возможность быстрой разработки продуктов и сервисов, использующих сетевые взаимодействия, на платформе Java.

Java 2 Platform, Standard Edition (J2SE platform) (платформа J2SE)
Ядро платформы технологии Java.

Java 2 Platform, Enterprise Edition (J2EE platform) (платформа J2EE)
Среда для разработки корпоративных приложений. Платформа J2EE состоит из набора услуг, интерфейсов прикладного программирования (APIs) и протоколов, обеспечивающих функциональные возможности для разработки многоуровневых Web-приложений.

Java 2 SDK, Enterprise Edition
Реализация платформы J2EE компании Sun. Данная реализация включает описание работы платформы J2EE.

JavaBeans
Модель переносимых платформонезависимых компонентов многократного использования.

Java Blend
Продукт, позволяющий разработчику упростить разработку приложений баз данных при помощи отображения записей баз данных в объекты языка Java и Java-объектов - в базы данных.

Java Card API
API для систем с минимальным набором ресурсов, в частности для смарт-карт. Среда прикладных программных средств, соответствующая стандарту ISO 7816-4 для интеллектуальных карт.

JavaCheck
Инструмент для проверки соответствия приложений и апплетов языка Java.

JavaChip
Процессор фирмы Sun, выполняющий байт-код виртуальной машины Java*. На компьютере с процессором JavaChip байт-код минует эмуляцию Java-машины на какой-либо платформе, исполняясь непосредственно аппаратным процессором.

Java Compatibility Kit (JCK)
Набор испытательных программ и инструментальных средств, используемых для проверки совместимости реализации платформы Java соответствующим спецификациям Java-платформ, а также эталонным реализациям программ Java. TCK для Java 2 Standard Edition. См. TCK.

Java Database Connectivity - JDBC (интерфейс JDBC)
Промышленный стандарт для независимого от базы данных взаимодействия Java-платформы и широкого диапазона баз данных. JDBC определяет API для доступа к базам данных из Java-приложений.

Java Developer Connection
Служба, предназначенная для индивидуальных разработчиков, предоставляющая интерактивное обучение, скидки на продукты, специальные статьи, информацию об ошибках, а также возможности раннего доступа к новым продуктам.

Java Development Kit - JDK (комплект разработчика для Java)
Среда программирования для написания апплетов и приложений в языке программирования Java.

Java Electronic Commerce Framework
Структурированная архитектура для разработки приложений электронной коммерции в языке программирования Java.

Java Enterprise API
Данный API упрощает создание крупномасштабных приложений и приложений баз данных, которые совместно используют мультимедийные данные с другими приложениями в пределах организации или через Internet. В семействе Java Enterprise API разработано четыре интерфейса прикладного программирования.

Java Foundation Classes - JFC (библиотека базовых классов Java)
Дополнительные библиотеки классов графического пользовательского интерфейса (Graphical User Interface - GUI), добавляемые к абстрактному оконному интерфейсу (Abstract Window Toolkit - AWT).

Java IDL
Технология, обеспечивающая функциональную совместимость и способность к взаимодействию CORBA и J2EE-платформы. Эти возможности позволяют приложениям J2EE вызывать операции удаленных сетевых служб, используя OMG IDL и IIOP.

Java Interface Definition Language (IDL)
API, написанные на языке программирования Java, которые обеспечивают функциональную совместимость и способность к взаимодействию с CORBA (Common Object Request Broker Architecture).

JavaMail
API для отправки и получения сообщений.

Java Media APIs
Набор интерфейсов прикладного программирования (APIs) для интеграции аудио и видео файлов, двумерных шрифтов, графики и изображений, а также трехмерных моделей и телефонии.

Java Media Framework
Ядро структуры поддерживает часы для синхронизации различных потоков (например, аудио и видео сигналов). Standard extension framework позволяет пользователям организовать потоки аудио и видео информации.

Java Message Service - JMS
Интерфейс прикладного программирования (API) для использования корпоративных систем передачи сообщений, таких как IBM MQ Series, TIBCO Rendezvous и т.д.

Java Naming and Directory Interface (JNDI)
Стандартный API к корпоративной службе каталогов.

JavaOS (операционная система Java)
Операционная система, основанная на технологии Java и оптимизированная для работы на различных платформах. Операционная среда JavaOS обеспечивает работу Java-приложений непосредственно на аппаратных платформах, минуя ведущую операционную систему.

JavaPlan
Инструмент для объектно-ориентированного проектирования и схематического изображения, написанный на языке программирования Java.

Java Platform (платформа Java)
Состоит из языка Java, предназначенного для написания программ, набора интерфейсов прикладного программирования (APIs), библиотек классов, других программ, используемых при разработке и компиляции, программ проверки ошибок, а также виртуальной машины Java, которая загружает и выполняет файлы классов.

Кроме того, платформа Java подчиняется набору требований совместимости для гарантии непротиворечивых и совместимых реализаций. Реализации, выполняющие требования совместимости, могут приобретать квалификацию заданной марки совместимости фирмы Sun. Java 2 - настоящее поколение платформы Java.

Java Platform Editions (издания платформы Java)
"Издание" платформы Java - это окончательная и согласованная версия платформы Java, которая обеспечивает функциональные возможности, необходимые в широком секторе рынка.

Издание составлено из двух видов API: (i) "основные пакеты", которые являются необходимыми для всех реализаций данного издания платформы; (ii) "дополнительные пакеты", которые доступны данному изданию платформы и могут поддерживаться совместимыми реализациями.

Существует три различных издания платформы Java:

  • Java 2 Platform, Enterprise Edition:
    Издание платформы Java, используемое на предприятиях и предназначенное для разработки и развития многоуровневых приложений, управляемых центральным сервером.
  • Java 2 Platform, Standard Edition:
    Издание платформы Java, предназначенное для разработки, развития и управления межплатформенными универсальными приложениями.
  • Java 2 Platform, Micro Edition:
    Издание платформы Java, предназначенное для малых автономных потребителей, с целью разработки, развития и управления приложений, варьирующихся от смарт-карт до обычных вычислительных устройств.

Java Remote Method Invocation (RMI)
Распределенная объектная модель для Java-программы, в которой методы и удаленные объекты, написанные на языке программирования Java, могут быть вызваны другой виртуальной машиной Java, возможно, расположенной на другом компьютере.

Java Runtime Environment (JRE)
Подмножество комплекта разработчика Java (Java Developer Kit - JDK) для конечных пользователей и разработчиков, которые хотят самостоятельно настроить оперативные средства управления работой программы (run-time environment). Оперативные средства включают в себя виртуальную машину Java*, классы ядра Java и вспомогательные файлы.

JavaSafe
Инструмент для отслеживания и управления изменениями исходного файла, написанного на языке программирования Java.

JavaScript (язык сценариев JavaScript)
Язык сценариев, который используется как браузерами, так и Web-серверами. Подобно всем языкам сценариев, предназначен главным образом для интеграции компонент и пользовательского ввода.

Java Server Pages (JSP) Расширяемая Web-технология, использующая данные шаблона, заказные элементы, языки сценариев и серверные объекты Java для предоставления клиенту динамического содержания. Обычно, данные шаблона - это HTML или XML элементы, а клиент - это Web-браузер.

JAX
JAX относится к набору интерфейсов прикладного программирования (APIs), который предназначен для управления различными операциями, включающими данные, определенные посредством XML. Сюда входят такие операции как синтаксический анализ XML, регистрация в репозиториях ebXML или UDDI, обмен сообщениями между приложениями, привязка данных и удаленный вызов процедур.

JSP action (действие Java Server Pages {JSP})
JSP элемент, который может действовать на неявные объекты и другие серверные объекты или определять новые переменные создания сценария. Действия придерживаются синтаксиса XML для элементов с начальным тэгом, телом и конечным тэгом; если тело пусто, может использоваться синтаксис пустого тэга. Тэг должен использовать префикс.

JSP action, standard (стандартное действие Java Server Pages)
Действие, которое определено спецификацией JSP и всегда доступно JSP-файлу без импортирования.

JSP action, custom (специальное действие Java Server Pages)
Действие, описанное с помощью тэгов и набора классов Java, включенных в страницу JSP с помощью тэговых дескрипторов.

JSP application (приложение JSP)
Автономное Web- приложение, написанное с использованием технологии Java Server Pages и включающее JSP файлы, сервлеты, HTML файлы, изображения, апплеты и компоненты JavaBeans.

JSP container (контейнер JSP)
Контейнер, предоставляющий те же услуги, что и сервлет-контейнер, а также механизм интерпретации и переработки JSP страниц в сервлеты.

JSP container, distributed (распределенный контейнер JSP)
JSP контейнер, который может запускать Web-приложения, помеченные как распределенные и выполняемые одновременно на нескольких виртуальных машинах Java. При этом виртуальные машины могут быть запущены, как на одном, так и на разных компьютерах.

JSP declaration (объявление JSP)
Элемент сценариев JSP, который объявляет методы и переменные в JSP файле.

JSP directive (директива JSP)
Элемент JSP, который дает команды JSP контейнеру и интерпретируется во время трансляции.

JSP element (элемент JSP)
Часть JSP страницы, которая распознается JSP транслятором. Элемент JSP может быть директивой, действием или элементом сценария.

JSP expression (выражение JSP)
Элемент сценария, который содержит допустимое выражение языка сценариев, вычисленное, преобразованное в строку и помещенное в неявный выходной объект.

JSP file (файл JSP)
Файл с расширением .jsp, который создается разработчиком при помощи стандартных тэгов HTML, основных JSP тэгов и инструкций языка сценариев, для отображения динамических страниц в Web-браузере.

JSP page (страница JSP)
Текстовый документ, использующий фиксированные шаблонные данные и элементы JSP. Описывает, как обработать запрос.

JSP элемент сценария
Объявление JSP, скриптлет или выражение, синтаксис которого определен спецификацией JSP и содержимое которого написано согласно языку сценариев, используемому в странице JSP. Спецификация JSP описывает синтаксис и семантику для того случая, когда атрибут языка страницы - java.

JSP scriptlet (скриптлет JSP)
Элемент сценария JSP, содержащий любой фрагмент кода, допустимый в том языке сценариев, который используется на JSP странице. Спецификация JSP определяет, что является допустимым скриптлетом для того случая, когда атрибут языка страницы - java.

JSP tag (тэг JSP)
Текст между левой и правой угловыми скобками, который используется в файлах JSP, как часть элемента JSP. В отличие от данных, тэг является элементом разметки документа, т.к. он выделен угловыми скобками.

JSP tag library (библиотека тэгов JSP)
Совокупность тэгов, описанных посредством библиотечных дескрипторов и классов Java. Библиотека тэгов JSP может импортироваться в любой JSP файл и использоваться с различными языками сценариев.

Java Studio
Инструментальный комплекс для построения Java-программ из готовых компонент, основанный на визуальном стиле проектирования и предназначенный для непрограммистов.

Java Technologies (технологии Java)
Ряд технологий по созданию и безопасной работе программного обеспечения, как в автономных, так и в сетевых средах.

Java Transaction API (JTA)
API, позволяющий приложениям и сервлетам J2EE иметь доступ к транзакциям.

Java Transaction Service (JTS)
Определяет реализацию менеджера транзакций, который поддерживает JTA и осуществляет Java отображение спецификации OMG Object Transaction Service (OTS) 1.1 на уровень ниже API.

Java virtual machine - JVM* (виртуальная машина Java*)
Программный "механизм выполнения", который безопасно выполняет байт-коды файлов классов Java на микропроцессоре (компьютера или другого электронного устройства).

Механизм выполнения Java HotSpot - это высокоэффективный механизм для среды выполнения Java программ, который представляет собой адаптивный компилятор, динамически оптимизирующий работу приложений.

Виртуальная машина KJava - малогабаритная, высоко оптимизированная основа среды выполнения программ (runtime environment) в Java 2 Platform, Micro Edition. KJava разработана на основе виртуальной машины Java и предназначена для малых устройств связи. Ее размер составляет от 30 до 128 Кб, в зависимости от функциональных возможностей устройства.

Виртуальная машина Java Card - малогабаритная, высоко оптимизированная основа среды выполнения программ (runtime environment) в Java 2 Platform, Micro Edition. KJava разработана на основе виртуальной машины Java и предназначена для смарт-карт и других устройств с ограниченной памятью (порядка 24Кб ПЗУ, 16Кб EEPROM и 512б ОЗУ).

Java Web Server (Web-сервер Java)
Удобное, открытое, легко администрируемое, безопасное, платформонезависимое решение для ускорения и простоты разработки Internet/Intranet Web-страниц. Обеспечивает немедленное повышение производительности для трудоемких, полнофункциональных серверных приложений Java.

Java Workshop
Законченный набор инструментов, интегрированный в единую среду программирования с использованием Java технологий. Программное обеспечение Java Workshop использует модульную структуру, которая позволяет легко подключать новые инструментальные средства.

Java wallet
Пользовательский интерфейс, основанный на Java Electronic Commerce Framework, предназначенный для осуществления интерактивных покупок, передачи данных и выполнения административных функций.

JavaSpaces
Технология, содержащая механизмы распределенной работы и обмена данными при программировании на языке Java.

JavaSoft
Ранее филиал компании Sun Microsystems, в настоящее время известный как подразделение Sun Microsystems Java Software.

JDBC
См. интерфейс JDBC (Java Database Connectivity - JDBC).

JDK
См. комплект разработчика для Java (Java Development Kit - JDK).

JFC
См. библиотека базовых классов Java (Java Foundation Classes - JFC).

Jini Technology (технология Jini)
Набор интерфейсов прикладного программирования (APIs) Java, которые могут быть включены в дополнительный пакет к любому изданию платформы Java 2. Jini позволяет обеспечивать совместную работу в сети различных устройств и служб, а также устраняет необходимость системного или сетевого административного вмешательства пользователя.

В настоящее время технология Jini является дополнительным пакетом, доступным любой Java платформе.

Java Management API - JMAPI
Совокупность Java классов и интерфейсов, позволяющих разработчику создавать системные, сетевые и служебные приложения.

JMS
См. Java Message Service.

JNDI интерфейс
См. Java Naming and Directory Interface.

JPEG - Joint Photographic Experts Group (стандарт JPEG)
Стандарт сжатия файлов изображений, установленный группой экспертов по машинной обработке фотографических изображений. Сильное сжатие достигается ценой внесения искажений в изображение, которые почти всегда являются незаметными.

JRE
См. Java Runtime Environment.

Just-in-time (JIT) Compiler (компилятор JIT)
Компилятор, динамически ("на лету") преобразующий байт-код в объектный код целевой платформы. Его применение приводит к значительному ускорению выполнения Java-программы.

JVM
См. виртуальная машина Java*.

K

keyword (ключевое слово)
Слово, которое зарезервировано языком программирования Java, и поэтому не может быть именем переменной или метода.

L

lexical (лексический)
Соответствующий уровню лексем (идентификаторов, чисел, изображений строк и т.д.) языка программирования. Лексический анализ - фаза компилятора, на которой последовательность символов файла исходного текста преобразуется в последовательность лексем.

linker (компоновщик)
Модуль, который формирует запускаемую, законченную программу из составных модулей машинного кода. Компоновщик Java создает работоспособную программу из откомпилированных классов. См. также компилятор, интерпретатор, система поддержки исполнения программ.

literal (литерал)
Основное представление любого целого, символьного значения или значения с плавающей запятой. Например, 3.0 - литерал с плавающей запятой двойной точности, "а" - символьный литерал.

local variable (локальная переменная)
Элемент данных, известный в пределах блока, но недоступный вне блока. Например, любая переменная, определенная внутри метода, является локальной и не может использоваться вне этого метода.

long
Ключевое слово языка программирования Java, используемое для определения переменных типа long.

M

member (элемент)
Поле или метод класса. Пока не оговорено обратное, член не является статическим.

method (метод)
Функция, определенная в классе. См. также метод экземпляра, метод класса. Пока не оговорено обратное, метод не является статическим.

method permission (разрешение на вызов метода)
Разрешение на вызов указанной группы методов "домашнего" или удаленного интерфейса корпоративного компонента (enterprise bean).

module (модуль)
Программный модуль, который состоит из одного или более компонентов J2EE, принадлежащих контейнеру одного типа, и из дескриптора размещения этого типа. Существует три типа модулей: EJB, Web и клиентские приложения. Модули можно использовать автономно или собирать в приложения.

Mosaic
Программа c несложным графическим интерфейсом (GUI), предназначенная для простого доступа к данным, хранящимся в Internet. Данные могут быть обычными файлами или гипертекстовыми документами. Mosaic была разработана в NCSA.

multithreaded (многопоточный)
Описывает программу, спроектированную и реализованную в виде совокупности параллельных потоков управления (threads), синхронизированных между собой по общим ресурсам и событиям. См. также поток.

mutual authentication (взаимная аутентификация)
Процесс, при котором клиент использует сертификат с открытым ключом для установления своей идентичности и поддерживает защиту своего контекста.

N

native
Ключевое слово языка программирования Java, используемое в объявлении метода для указания на то, что метод реализован не в файле Java, а на другом языке.

National Center for Supercomputer Applications - NCSA (Национальный центр по приложениям для суперкомпьютеров)
Исследовательский центр, в котором была разработана программа Mosaic.

new
Ключевое слово языка программирования Java, используемое для создания нового экземпляра класса.

null
Тип null имеет единственное значение - "пустую" ссылку, представленную литералом null, который сформирован из символов ASCII. Литерал null всегда имеет тип null.

O

object (объект)
Основной компоновочный блок объектно-ориентированных программ. Каждый объект программного модуля состоит из данных (переменные экземпляра) и функциональных возможностей (методы экземпляра). См. также класс.

object-oriented design (объектно-ориентированное проектирование)
Метод проектирования программного обеспечения, позволяющий моделировать абстрактные или реальные объекты при помощи классов и объектов.

octal (восьмеричный)
Система счисления с основанием 8. Знаки 0-7 представляют цифры. В программе, написанной на языке Java, восьмеричные числа должны начинаться с символа 0. См. также шестнадцатеричный.

Open Net Environment - ONE (открытое сетевое окружение)
Сетевая среда, которая была разработана компанией Sun Microsystems и поддержана многими ведущими производителями. Описывает всестороннюю архитектуру для создания, сборки и использования сетевых услуг. ONE платформонезависима и полностью основана на открытых стандартах. Sun ONE - конкретная реализация данной архитектуры, разработанная компаниями Sun и iPlanet.

Optional Package (дополнительный пакет)
Набор API в издании платформы Java, который может быть доступным или поддерживаться в совместимой реализации.

По мере необходимости, дополнительные пакеты могут становиться необходимыми в издании.

Object Request Broker - ORB (посредник запросов к объектам)
Библиотека, позволяющая объектам CORBA определять местонахождение и устанавливать связь друг с другом.

OS principal (принцип)
Свойство (principal), присущее той операционной системе, на которой запущена платформа J2EE.

Object Transaction Service (OTS)
Интерфейсы, позволяющие объектам CORBA участвовать в транзакциях.

overloading (перегрузка {операций})
Использование одного идентификатора для ссылки на разные элементы в одной области действия. В языке программирования Java можно перегружать методы, однако, нельзя перегружать переменные или операторы.

overriding (замещение)
Означает другую реализацию метода в подклассе класса, первоначально определившего метод.

P

package (пакет)
Группа типов. Пакеты объявляются при помощи ключевого слова package.

passivation (пассивация)
Процесс передачи корпоративного компонента (enterprise bean) из памяти во вторичное устройство хранения данных. См. также активация.

peer (одноранговые)
В организации сетей любые функциональные единицы, находящиеся на одном уровне.

persistence
Протокол передачи состояния сущности (entity bean) между переменными ее экземпляра и базой данных.

PersonalJava
Среда выполнения Java для сетевых приложений на персональных устройствах потребителя (домашнего, мобильного или офисного использования).

pixel (пиксель)
Элемент площади изображения, например, экрана монитора или напечатанной страницы. Каждый пиксель является индивидуально доступным.

Portable Object Adapter - POA
Стандарт CORBA для создания серверных приложений, которые переносимы между различными посредниками запросов к объектам (ORBs).

Portable Operating System Interface - POSIX (интерфейс переносимой операционной системы)
Стандарт, который определяет языковой интерфейс между операционной системой UNIX и прикладными программами посредством минимального набора поддерживаемых функций.

primary key (первичный ключ)
Объект, уникально идентифицирующий сущность (entity bean).

principal (принцип)
Отличительная черта, присвоенная сущности в результате аутентификации.

private
Ключевое слово языка программирования Java, используемое при объявлении метода или переменной. Указывает на то, что к методу или переменной класса не могут обращаться элементы других классов.

privilege (привилегия)
Атрибут защиты, который не имеет свойства уникальности и который может быть использован несколькими principals. Пример привилегии - группа.

process (процесс)
Виртуальное адресное пространство, содержащее один или более потоков.

property (свойство)
Характеристика объекта, которую может устанавливать пользователь. Например, цвет окна.

Profiles (профили)
Наборы Java API, которые служат дополнением к изданиям платформ Java и обеспечивают дополнительные возможности. Профили также могут включать другие определенные профили. Реализация профиля нуждается в издании Java Platform для создания законченной разработки и среды ее использования на целевом вертикальном рынке. Каждый профиль подчиняется связанному набору требований совместимости.

Профили могут использоваться одним или несколькими изданиями.

Примеры профилей в Java 2 Platform, Micro Edition: PersonalJava, Java Card.

protected
Ключевое слово языка программирования Java, используемое при объявлении метода или переменной. Указывает на то, что к методу или переменной класса могут обращаться другие элементы данного класса, его подклассов или классов из того же пакета.

private
Ключевое слово языка программирования Java, используемое при объявлении метода или переменной. Указывает на то, что к методу или переменной класса могут обращаться элементы других классов.

Q

R

raster (растр)
Двумерная прямоугольная сетка пикселей.

realm (область)
См. область политики безопасности. Строка, проходящая базовую аутентификацию, как часть HTTP-запроса, которая определяет пространство защиты. Защищенные ресурсы на сервере могут находиться в разных пространствах защиты, каждое со своей схемой аутентификации и/или базой данных авторизации.

re-entrant enterprise bean (реентерабельный корпоративный компонент)
Корпоративный компонент, который может обрабатывать несколько одновременных или вложенных вызовов, не пересекающихся друг с другом.

reference (ссылка)
Элемент данных, значение которого является адресом памяти.

Reference Implementation - RI (ссылочная реализация)
Прототип реализации спецификации Java-технологии. Является неотъемлемой частью любой Java-технологии и служит доказательством того, что данная Java-технология может быть реализована на практике.

remote interface (удаленный интерфейс)
Один из двух интерфейсов корпоративной компоненты (enterprise bean). Удаленный интерфейс определяет бизнес-методы, вызываемые клиентом.

remove method (метод удаления)
Метод, определенный в "домашнем" интерфейсе и вызываемый клиентом для уничтожения корпоративной компоненты (enterprise bean).

resource adapter (адаптер ресурсов)
Программный драйвер системного уровня, используемый EJB-контейнером или клиентским приложением для связи с EIS. Адаптер ресурсов специфичен для каждой EIS. Он представляет собой библиотеку, и используется в пределах адресного пространства сервера или клиента, которые используют адаптер. Адаптер ресурсов подключается к контейнеру. Прикладные компоненты, содержащиеся в контейнере, используют API (представленный адаптером) или инструментально созданные высокоуровневые абстракции для доступа к низкоуровневой EIS. Адаптер ресурса и EJB-контейнер взаимодействуют для того, чтобы обеспечить низкоуровневые механизмы - транзакции, безопасность, организация связного пула - для связи с EIS.

resource manager (менеджер ресурсов)
Обеспечивает клиенту доступ к набору общедоступных ресурсов. Менеджер ресурсов участвует в транзакциях, которые управляются и координируются менеджером транзакций. Менеджер ресурсов обычно находится в другом адресном пространстве или на другой машине. Замечание: к EIS обращаются, как к менеджеру ресурсов, когда она упомянута в контексте управления ресурсами и транзакциями.

resource manager connection (соединение с менеджером ресурсов)
Объект, представляющий собой сеанс связи с менеджером ресурсов.

resource manager connection factory (мастер соединения с менеджером ресурсов)
Объект, используемый для создания сеанса связи с менеджером ресурсов.

return
Ключевое слово языка программирования Java, используемое для окончания выполнения метода. За ним может следовать значение, возвращаемое методом.

Request for Enhancement - RFE (запрос на улучшение)

RMI
См. Java Remote Method Invocation.

role (development) (роль разработки)
Функция, выполняемая человеком в стадии развития приложения, разрабатываемого с помощью технологии J2EE. Примеры ролей: поставщик программных компонент (Application Component Provider), компоновщик приложения (application assembler), "разместитель" (deployer), поставщик платформы J2EE (J2EE Platform Provider), поставщик EJB-контейнера (EJB Container Provider), поставщик EJB-сервера (EJB Server Provider), поставщик Web-контейнера (Web Container Provider), поставщик Web-сервера (Web Server Provider), поставщик инструментов (Tool Provider), системный администратор (System Administrator).

role (security) (роль безопасности)
Абстрактная логическая группировка пользователей, осуществляемая компоновщиком приложения. Когда приложение установлено, роли ставятся в соответствие идентичностям безопасности, таким как principals или группы.

role mapping (распределение ролей)
Процесс объединения групп, распознанных контейнером, в роли безопасности, которые определены в дескрипторе размещения. Роли безопасности должны быть составлены "разместителем" перед установкой контейнера на сервер.

rollback (откат)
Момент транзакции, когда все изменения, вносимые в базу данных, отменяются.

root (корень)
Элемент иерархии, из которого происходят все элементы. Ни один элемент не может находиться в иерархии выше "корня". См. также иерархия, класс, пакет.

Remote Procedure Call - RPC (вызов удаленной процедуры)
Протокол, позволяющий приложениям вызывать процедуры, физически расположенные в другой части сети.

runtime system (система поддержки исполнения программ)
Программная среда, в которой могут работать программы, откомпилированные для виртуальной машины Java*. Система поддержки исполнения включает весь код, необходимый для того, чтобы загружать программы, написанные на Java, динамически связывать "родные" методы, управлять памятью, обрабатывать исключительные ситуации, а также реализацию виртуальной машины Java.

S

Simple API for XML - SAX (простой API для XML)
Управляемый событиями, последовательный механизм доступа к XML документам.

Sandbox
Содержит множество взаимодействующих системных компонент, начиная от менеджеров безопасности, которые выполняются как часть приложения, и заканчивая мерами безопасности, встроенными непосредственно в виртуальную машину Java* и язык Java. Sandbox гарантирует, что ненадежные и, возможно, злонамеренные приложения не смогут получить доступ к системным ресурсам.

scope (область действия)
Характеристика идентификатора, определяющая, где может использоваться данный идентификатор. Большинство идентификаторов в языке программирования Java имеют либо локальную область действия, либо область действия - класс. Для переменных экземпляров и классов, а также методов областью действия является класс; они могут использоваться вне класса и его подклассов, только если перед ними ставится имя экземпляра класса или (в случае переменных и методов класса) имя самого класса. Все другие переменные объявляются внутри методов и имеют локальную область действия; они могут использоваться только внутри блока.

Secure Socket Layer - SSL (протокол безопасных соединений)
Протокол, который позволяет шифровать сообщения, передаваемые между Web-браузером и сервером в целях безопасности.

security attributes (атрибуты безопасности)
Набор свойств, связанных с principal. Атрибуты безопасности могут быть связаны с principal посредством протокола аутентификации и/или поставщиком продуктов J2EE (J2EE Product Provider).

security constraint (ограничения безопасности)
Декларативный способ аннотирования необходимой защиты содержимого сети. Ограничение безопасности состоит из совокупности Web-ресурсов, ограничения авторизации, ограничения пользовательских данных.

security context (контекст безопасности)
Объект, включающий разделяемые свойства для описания безопасности сущностей.

security permission (право безопасности)
Механизм, определенный J2SE и используемый платформой J2EE для определения программных ограничений, наложенных на поставщиков программных компонент (Application Component Providers).

security permission set (набор прав безопасности)
Минимальный набор прав безопасности, обеспечиваемый поставщиком программных компонент (Application Component Provider) для выполнения каждого типа компонент.

security policy domain (область политики безопасности)
Область, в переделах которой определена и приведена в исполнение администратором политика безопасности. Область политики безопасности имеет следующие характеристики:

  • обладает набором пользователей (или principals);
  • использует хорошо определенный протокол аутентификации пользователей (или principals);
  • может иметь группы для упрощения настройки политики безопасности.

security role
См. роль безопасности (role(security)).

security technology domain (область технологии безопасности)
Область, в пределах которой для осуществления политики безопасности используется один и тот же механизм. В пределах единой области технологии безопасности может существовать несколько областей политики безопасности.

server principal
Принцип ОС, в соответствии с которым работает сервер.

servlet (сервлет)
Java программа, которая расширяет функциональные возможности Web-сервера, динамически генерируя содержание и взаимодействуя с Web-клиентами при помощи принципа запрос-ответ.

servlet container (контейнер сервлета)
Контейнер, обеспечивающий сетевые службы, при помощи которых посылаются запросы и ответы, декодируются запросы и форматируются ответы. Все контейнеры сервлетов должны поддерживать HTTP-протокол, но могут также поддерживать дополнительные протоколы, например, HTTPS.

servlet container, distributed (распределенный контейнер сервлета)
Контейнер сервлета, запускающий Web-приложения, которые помечены как распределенные и выполняются на нескольких виртуальных машинах Java. При этом виртуальные машины могут быть запущены, как на одном, так и на разных компьютерах.

servlet context (контекст сервлета)
Объект, содержащий представление (вид) Web-приложения, в котором запущен сервлет. Используя контекст, сервлет может вести журнал событий, получать URL-ссылки на ресурсы, а также устанавливать и хранить атрибуты, которые могут использоваться другими сервлетами в приложении.

servlet mapping (отображение сервлета)
Определяет связь между структурой URL и сервлетом. Используется для отображения запросов в сервлеты. Если контейнер, обрабатывающий запрос, является JSP-контейнером, то неявно отображается URL, содержащий расширение .jsp.

session (сессия)
Объект, используемый сервлетом, для прослеживания взаимодействий пользователя с Web-приложением при помощи множества HTTP-запросов.

session bean (сессионный компонент)
Корпоративный компонент (enterprise bean), который создается клиентом и обычно существует только в течение одной клиент-серверной сессии. Сессионный компонент выполняет для клиента вычислительные операции и организует доступ к базе данных. В случае сбоя системы сессионный компонент не восстанавливается. Объекты сессионных компонент могут не менять своего состояния или поддерживать диалоговое состояние в процессе выполнения методов и транзакций. Если объект поддерживает состояние, то EJB-контейнер управляет этим состоянием, если объект должен быть удален из памяти. Однако объекты сессионного компонента должны управлять собственными хранимыми данными.

short
Ключевое слово языка программирования Java, используемое для определения переменных типа short.

single precision (одинарная точность)
В спецификации языка Java описывает число с плавающей запятой, занимающее 32 бита данных. См. также двойная точность.

Standardized Generalized Markup Language - SGML (стандартный язык обобщенной разметки)
Стандарт ISO/ANSI/ECMA для определения структуры и управления содержимым любого электронного документа.

Smart Web Services
Расширяют основную концепцию сетевых услуг, добавляя пользовательский контекст, и способны модифицировать свои действия, чтобы следить за изменениями текущего состояния клиента. Сюда входят классические дескрипторы "кто, что, когда, где, почему", которые объединяются для определения пользовательского контекста в данный момент.

The Simple Object Access Protocol - SOAP
Использует основанное на XML структурирование данных и HTTP для того, чтобы определить стандартизованные методы для вызова методов объектов, распределенных в различных средах по всей Internet.

Structured Query Language - SQL (язык структурированных запросов)
Стандартизованный язык реляционных баз данных, предназначенный для определения объектов баз данных и манипулирования данными.

stateful session bean (сессионный компонент с диалоговым состоянием)
Сессионный компонент с диалоговым состоянием.

stateless session bean (сессионный компонент, не имеющий состояния)
Сессионный компонент, не имеющий состояния. Все экземпляры такого компонента идентичны.

static
Ключевое слово языка программирования Java, используемое для определения переменной класса (типа). Классы обеспечивают только одну копию таких переменных, не зависимо от того, сколько экземпляров класса было создано. Слово static также может использоваться при определении метода класса. Такие статические методы вызываются от имени не экземпляра объекта, а его типа (класса), и могут, в свою очередь, оперировать только статическими переменными.

static field (статическое поле)
Другое название переменной класса.

static method (статический метод)
Другое название метода класса.

stream (поток)
Последовательность байтов данных, пересылаемых от отправителя к получателю. Существует две основные категории потоков, поэтому пакет java.io включает два абстрактных класса (InputStream и OutputStream).

subarray (подмассив)
Массив, содержащийся в другом массиве.

subclass (подкласс)
Класс, который "произведен" из другого класса. См. также суперкласс, супертип.

subtype (подтип)
Если тип X "расширяет" или реализует тип Y, то X - подтип типа Y. См. также супертип.

superclass (суперкласс)
Класс, из которого "произведены" другие классы. См. также подкласс, подтип.

super
Ключевое слово языка программирования Java, используемое для доступа к членам класса, наследуемого классом, из которого производится вызов.

supertype (супертип)
Все интерфейсы или классы, расширяемые или реализуемые данным типом. См. также подтип, суперкласс.

switch
Ключевое слово языка программирования Java, используемое для определения переменной, которая в дальнейшем может быть использована ключевым словом case для выполнения блока инструкций.

Swing
Кодовое название совокупности графических компонентов, которые выполняются на любой платформе, поддерживающей виртуальную машину Java. Данные компоненты могут обеспечивать большие функциональные возможности, вследствие того, что они целиком написаны на языке Java. См. также AWT.

synchronized
Ключевое слово языка программирования Java, которое при применении к методу или блоку кода, гарантирует, что данный код будет выполняться не более чем одним потоком одновременно.

System Administrator (системный администратор)
Человек, ответственный за конфигурирование и администрирование компьютеров компании, сетей и систем программного обеспечения.

T

TCP/IP (TCP/IP)
Протокол управления передачей данных, основанный на IP. Internet-протокол, который обеспечивает надежную транспортировку потоков данных между компьютерами. См. также IP.

Technology Compatibility Kit - TCK (Испытатель Совместимости Технологии {TCK})
Набор тестов, инструментов, сопутствующих утилит и документации, которые позволяют реализатору Спецификации той или иной технологии определить, соответствует ли его реализация заданной Спецификации. Любая Java-технология состоит из Спецификации, ТСК и ссылочной реализации (reference implementation).

Thin Client ("тонкий" клиент)
Система, использующая очень упрощенную операционную систему, не требующая локального системного администрирования и выполняющая приложения, загруженные из сети.

this
Ключевое слово языка Java, которое может использоваться для ссылки на экземпляр класса, в котором используется эта ссылка. Слово this может использоваться для доступа, как к полям, так и к методам класса.

thread (процесс {поток})
Основная единица выполнения программы. Процесс может иметь несколько потоков, работающих одновременно и выполняющих различные задачи, такие как, ожидание события или исполнение трудоемкой по времени работы, окончание которой не требуется для дальнейшего выполнения программы. После выполнения потоком своей работы он приостанавливается или уничтожается. См. также процесс.

throw
Ключевое слово языка Java , которое позволяет пользователю сгенерировать исключительную ситуацию или любой класс, реализующий "throwable" интерфейс (т.е. интерфейс, позволяющий классу генерировать прерывания).

throws
Ключевое слово языка Java, используемое в описании метода и определяющее, какие исключительные ситуации не обрабатываются внутри метода, а передаются на следующий, более высокий уровень программы.

Tool Provider (поставщик инструментов)
Организация или поставщик программного обеспечения, предоставляющий инструменты, используемые для разработки, компоновки и внедрения J2EE приложений.

transaction (транзакция)
Минимальная единица работы по изменению данных. Транзакция включает в себя одну или несколько программных инструкций, которые могут выполниться только все вместе. Если хотя бы одна из инструкций не выполняется, происходит возврат в исходное состояние (откат). Транзакции разрешают одновременный доступ нескольким пользователям к одним и тем же данным.

transaction attribute (атрибут транзакции)
Значение, определяемое в дескрипторе внедряемой корпоративной компоненты (enterprise bean), которое используется в контейнере EJB для управления областью действия транзакции при вызове методов компоненты. Атрибут транзакции может принимать следующие значения: Required, RequiresNew, Supports, NotSupported, Mandatory, Never ("требуется", "требуется для новых", "поддерживается", "не поддерживается", "принудительно", "никогда").

transaction isolation level (уровень изоляции транзакции)
Степень видимости промежуточного состояния модифицируемых транзакцией данных для других параллельных транзакций и данных, модифицируемых другими транзакциями, для данной транзакции.

transaction manager (менеджер транзакции)
Обеспечивает сервисы и управляющие функции, требуемые для поддержки разграничения транзакции, управления ресурсами транзакции, синхронизации и прохождения содержания транзакции.

transient
Ключевое слово языка Java, которое определяет, что поле не является частью сериализуемой формы объекта. Когда объект сериализуется, значения его transient полей не включаются в представление сериализации, в то время как значения не transient полей включаются.

try
Ключевое слово языка Java, определяющее блок операторов, которые могут генерировать исключительные ситуации Java. При возникновении исключительной ситуации необязательный catch блок может обработать определенные исключительные ситуации, сгенерированные внутри блока try. Также необязательный блок finally будет выполнен независимо от того, генерировалась исключительная ситуация или нет.

type
Класс или интерфейс.

U

UDDI
Проект "Универсальное обнаружение и интеграция описаний" (The Universal Description Discovery and Integration - UDDI) обеспечивает глобальный, публичный, основанный на XML, онлайновый бизнес-регистр, в котором пользователи регистрируют и представляют свои web службы. UDDI представляет собой Internet-версию желтых страниц в справочнике телефонов.

Unicode (уникод)
16-битная кодовая таблица, определенная ISO 10646. См. также ASCII. Все исходные коды программной среды Java написаны в Unicode.

Uniform Resource Identifier - URI (унифицированный идентификатор ресурсов)
Компактная строка символов для идентификации абстрактного или физического ресурса. URI может быть или URL или URN. URL и URN представляют собой конкретные сущности, которые действительно существуют; URI является абстрактным суперклассом.

Uniform Resource Locator - URL (унифицированный указатель информационного ресурса)
Стандарт для записи текстовой ссылки на произвольные данные в WWW. URL выглядит следующим образом: "протокол://хост/локальная_информация", где протокол определяет конкретный протокол, используемый для доступа к объекту (например HTTP или FTP), хост определяет Internet-имя хоста, на котором объект находится, и локальная_информация - строка (часто имя файла), передаваемая обработчику протокола на удаленном хосте.

URL path
URL, передаваемый запросом HTTP для вызова сервлета. URL состоит из Context Path + Servlet Path + PathInfo, где Context Path является префиксом пути, ассоциируемым с контекстом сервлета. Этот сервлет является частью контекста. Если этот контекст является контекстом по умолчанию, находящимся в основном пространстве имен URL Web-сервера, префикс пути является пустой строкой. В противном случае префикс пути начинается с символа /, но не заканчивается символом /. Servlet Path - это участок пути, который прямо соответствует отображению, активизировавшему данный запрос. Этот путь начинается с символа /. PathInfo - это часть пути запроса, не являющаяся частью Context Path или Servlet Path.

URN (унифицированное имя ресурса)
Уникальный идентификатор, который идентифицирует сущность, но не показывает, где она расположена. Система может использовать URN для локального поиска сущности перед попыткой найти ее в Web. Этот идентификатор также позволяет изменение Web-ссылки при сохранении возможности нахождения сущности.

user data constraint (ограничитель данных пользователя)
Определяет, как должны быть защищены данные между клиентом и контейнером. Защита может быть предотвращением несанкционированного изменения данных либо предотвращением перехвата данных.

V

variable (переменная)
Элемент данных, имеющий идентифицирующее его имя. Каждая переменная имеет тип (например, int или Object) и область видимости. См. также переменная класса, переменная экземпляра, локальная переменная.

virtual machine (виртуальная машина)
Абстрактная спецификация для вычислительного устройства, которое может быть реализовано различным образом - программно или аппаратно. Вы компилируете последовательность команд виртуальной машины точно так же, как будто вы компилируете последовательность команд микропроцессора. Виртуальная машина Java состоит из байтовых команд, набора регистров, стека, "кучи" со сборкой "мусора" и областью для хранения методов.

vocabulary (словарь)
Обычно компьютерные программы пишутся и компилируются в машинные коды, которые прямо зависят от операционной системы, управляющей микропроцессором в компьютере. Java-платформа смягчает эту зависимость, обеспечивая модель, по которой программы пишутся, компилируются и могут быть переданы по сети и выполнены в любом месте, где присутствует полностью совместимая виртуальная машина.

Эта модель обеспечивает дополнительное преимущество в повышении безопасности. Во-первых, потому что программы могут быть проверены виртуальной машиной после того, как они были переданы по сети. И, во-вторых, потому что виртуальная машина может запустить программу в защищенном пространстве, которое предотвратит определенные разрушающие действия.

Разработчики программного обеспечения выбирают платформу Java потому, что это уменьшает стоимость и время написания и поддержки программного кода. Им больше не требуется переписывать программы для функционирования на различных компьютерах с различными операционными системами и микропроцессорами. Внедрение приложений Java технологии в компаниях и организациях выгодно, потому что это минимизирует стоимость покупки и модификации различных версий приложений для различных типов компьютеров и серверов внутри их сетей.

void
Ключевое слово языка Java, используемое в описании метода для указания на то, что метод не возвращает никакого значения. void может также использоваться как нефункциональный оператор.

volatile
Ключевое слово языка Java, используемое в описания переменной для указания на то, что переменная модифицируется асинхронно несколькими совместно выполняющимися потоками.

W

wait
Команда UNIX, которая будет ожидать завершения всех фоновых процессов и отчета об их статусе завершения.

Web application, distributable (Web-приложение, распределенное)
Web-приложение, использующее технологию J2EE и написанное таким образом, что оно может быть внедрено в Web контейнер, распределенный по нескольким виртуальным машинам Java, работающих на одном хосте или на различных хостах. Дескриптор "размещения" для такого приложения использует распределенный элемент.

Web component (Web-компонент)
Компонент, обеспечивающий сервисы в ответ на запросы, сервлеты или JSP страницы.

Web container (Web-контейнер)
Контейнер, обеспечивающий исполнение Web компонентов, удовлетворяющих правилам J2EE архитектуры. Эти правила определяют среду времени выполнения (runtime environment) для Web-компонентов, включая безопасность, совместную работу, управление жизненным циклом, транзакции, внедрение и другие службы. Контейнер, обеспечивающий такие же службы как JSP контейнер и интегрированный взгляд на API платформы J2EE. Web контейнер обеспечивается Web или J2EE сервером.

Web container, distributed (Web-контейнер, распределенный)
Web-контейнер, который может запускать Web-приложение, помеченное как распределенное, которое выполняется на нескольких виртуальных машинах Java, работающих на одном или на различных хостах.

Web server (Web-сервер)
Программа, обеспечивающая службы для доступа в Internet, Intranet, или Extranet. Web-сервер содержит Web-сайты, обеспечивая поддержку HTTP и других протоколов и выполняет серверные программы (такие как CGI-скрипты или сервлеты), которые выполняют определенные функции. Например, Web-контейнер обычно основан на Web-сервере для обеспечения обработки сообщений HTTP. Архитектура J2EE предполагает, что Web-контейнер предоставляется Web-сервером от одного и того же поставщика, т.е. не определяя правила между этими двумя сущностями. Web-сервер может предоставлять один или много Web-контейнеров.

Web Services (Web-службы)
Свободно собранные программные компоненты, способные взаимодействовать между собой по многочисленным сетям для предоставления определенного результата конечному пользователю. Во время работы они используют развивающуюся группу стандартов, которые определяют их (служб) описание и взаимодействие, таких как SOAP (простой протокол доступа к объектам), UDDI (универсальное обнаружение и интеграция описаний), XML (открытый язык меток), WSDL (язык описания Web-служб).

while
Ключевое слово языка Java, используемое для определения цикла, который повторяет блок инструкций. Условие продолжения цикла указывается как часть оператора while.

world readable files (общедоступные для чтения файлы)
Файлы в файловой системе, которые могут быть просмотрены (прочтены) любым пользователем. Например: файлы, расположенные на Web-серверах могут быть просмотрены пользователями Internet, если права файлов были установлены как "доступные для чтения".

wrapper
Объект, который инкапсулирует и уполномочивает другой объект на изменение своего интерфейса или поведения определенным образом.

Web Services Description Language - WSDL (язык описания Web-сервисов)
XML язык, который используется для описания Web-сервиса и для определения способа общения с Web-сервисом.

World Wide Web - WWW
"Всемирная паутина". Сеть систем и данных в них, т.е. часть Internet. См. также Internet.

X

Extensible Markup Language - XML (расширяемый язык меток)
Расширяемый язык разметки текстов (или текстовых документов). Дескрипторы размещения J2EE выражены при помощи XML.

Y

Z

*на данном Web-сайте, термин "виртуальная машина Java" или "JVM" означает виртуальную машину для платформы Java.


Sun Microsystems - Россия и СНГ - Программирование на Java: подробное руководство

Программирование на Java: подробное руководство

Введение в Java
Первое приложение
Первый аплет
Рисование в окне аплета
События
Компоненты
Работа с системой Layout Manager
Работа с панелями
Окна и диалоговые панели
Многопоточность
Работа с файлами
Сетевые приложения
Растровые изображения
Звук в аплетах Java

Александр Фролов, http://www.frolov.pp.ru/

Добро пожаловать в мир Java!

Вперед

В данном разделе представлены подробные материалы по языку Java и многочисленные примеры программирования на Java. Вы познакомитесь с принципами и технологиями, положенными в основу этого языка, изучите библиотеки классов Java, научитесь пользоваться современными визуальными средствами разработки приложений Java, такими как Java WorkShop и Java Studio.

Многочисленные примеры приложений и аплетов помогут вам в кратчайшие сроки освоиться в мире Java.

Оглавление

  • 1. ВВЕДЕНИЕ В JAVA
    • Инструментарий разработчика
    • Мобильность Java
    • Базовые типы данных
    • Библиотеки классов Java
    • Указатели, которых нет
    • Массивы в Java
    • Сборка мусора
    • Особенности реализации классов в Java
  • 2. ПЕРВОЕ ПРИЛОЖЕНИЕ
    • Установка Java WorkShop
    • Запуск Java WorkShop
    • Исходный текст приложения HelloJava
  • 3. ПЕРВЫЙ АПЛЕТ
    • Создание проект аплета
    • Исходный текст аплета
    • Методы в классе HelloApplet
    • Исходный текст документа HTML
    • Изменяем исходный текст аплета
    • Метод paint
    • Метод getAppletInfo
  • 4. РИСОВАНИЕ В ОКНЕ АПЛЕТА
    • Контекст отображения
    • Установка атрибутов контекста отображения
    • Определение атрибутов контекста отображения
    • Рисование геометрических фигур
    • Аплет Draw
    • Исходные тексты аплета Draw
    • Проект для аплета Draw
  • 5. СОБЫТИЯ
    • Как обрабатываются события
    • События от мыши
    • Аплет LineDraw
    • Исходный текст аплета LineDraw
    • Описание исходного текста
  • 6. КОМПОНЕНТЫ
    • Кнопки
    • Переключатели
    • Списки класса Choice
    • Списки класа List
    • Текстовое поле класса Label
    • Текстовое поле класса TextField
    • Многострочное текстовое поле класса TextArea
    • Аплет FormDemo
  • 7. РАБОТА С СИСТЕМОЙ LAYOUT MANAGER
    • Режимы системы Layout Manager
    • Режим FlowLayout
    • Режим GridLayout
    • Режим BorderLayout
    • Режим CardLayout
    • Режим GridBagLayout
    • Аплет FormLayout
  • 8. РАБОТА С ПАНЕЛЯМИ
    • Создание панелей
    • Добавление панелей
    • Добавление компонент в панели
    • Рисование в окне панели
    • Создание нового класса на базе класса Panel
    • Аплет Options
    • Исходный текст аплета Options
    • Описание исходного текста аплета Options
  • 9. ОКНА И ДИАЛОГОВЫЕ ПАНЕЛИ
    • Окна класса Frame
    • Меню в окне класса Frame
    • Класс Menu
    • Класс MenuItem
    • Создание диалоговых панелей
    • Приложение MenuApp
    • Исходный текст приложения MenuApp
    • Описание исходного текста приложения MenuApp
  • 10. МНОГОПОТОЧНОСТЬ
    • Процессы, потоки и приоритеты
    • Реализация многопоточности в Java
    • Применение многопоточности для анимации
    • Синхронизация потоков
    • Потоки-демоны
    • Аплет Rectangles
    • Исходные тексты аплета Rectangles
    • Описание исходных текстов аплета Rectangles
  • 11. РАБОТА С ФАЙЛАМИ
    • Классы Java для работы с потоками
    • Стандартные потоки
    • Создание потоков, связанных с файлами
    • Запись данных в поток и чтение данных из потока
    • Закрывание потоков
    • Принудительный сброс буферов
    • Потоки в оперативной памяти
    • Класс Stream Tokenizer для разбора входных потоков
    • Класс String Tokenizer
    • Работа с файлами и каталогами при помощи класса File
    • Произвольный доступ к файлам
    • Приложение StreamToken
    • Приложение DirectFile
  • 12. СОЗДАНИЕ СЕТЕВЫХ ПРИЛОЖЕНИЙ
    • Адрес IP и класс InetAddress
    • Универсальный адрес ресурсов URL
    • Класс URL в библиотеке классов Java
    • Передача данных с использованием сокетов
    • Работа с потоковыми сокетами
    • Класс Socket
    • Использование датаграммных сокетов
    • Связь приложений Java с расширениями сервера Web
    • Аплет ShowChart
    • Приложения SocketServ и SocketClient
    • Аплет Form
  • 13. РАСТРОВЫЕ ИЗОБРАЖЕНИЯ И АНИМАЦИЯ
    • Загрузка и рисование растрового изображения
    • Класс Image
    • Ожидание загрузки изображений
    • Видео в окне аплета
    • Аплет CDRotation
  • 14. ЗВУК В АПЛЕТАХ JAVA
    • Загрузка и проигрывание звуковых файлов
    • Аплет PlayClip

Обращаем ваше внимание на cловарь Java-терминов, подготовленный Sun Microsystems специально для российских разработчиков приложений Java.

Вперед


Sun Microsystems - Россия и СНГ - Программирование на Java

Программирование на Java
Введение в Java
Введение в Java
Инструментарий
Мобильность
Типы данных
Классы Java
Указатели
Массивы
Сборка мусора
Реализация классов

Назад Вперед

Казалось бы, на сегодняшний день изобретены уже все языки программирования, какие только можно придумать. Но нет - появился еще один, с названием Java. Этот язык сумел получить весьма заметную известность за последние несколько лет, так как он ориентирован на самую популярную компьютерную среду - сеть Internet и серверы Web.

Язык Java произошел от языка программирования Oak (а не от C++, как думают многие). Oak был приспособлен для работы в Internet и затем переименован в Java. Подробнее об этом вы можете узнать, прочитав статью по адресу http://www.sun.ru/java/start/intro/history.html.

Изучая Java, вы будете приятно удивлены тем, что его синтаксис близок к синтаксису языка C++. Унаследовав самое лучшее от языка программирования C++, язык Java при этом избавился от некоторых недостатков C++, в результате чего на нем стало проще программировать. В этом языке нет, например, указателей, которые сложны в использовании и потенциально могут послужить причиной доступа программы к не принадлежащей ей области памяти. Нет множественного наследования и шаблонов, хотя функциональные возможности языка Java от этого не пострадали. Если вы умеете программировать на C++, для вас не составит особого труда изучить язык Java.

Почему вам нужно изучать новый язык программирования Java?

Если ответить на этот вопрос кратко, то потому, что он специально ориентирован на самые передовые технологии, связанные с сетью Internet. Растущая популярность Internet и, в особенности, серверов Web, создает для программистов новые возможности для реализации своих способностей.

Огромное преимущество Java заключается в том, что на этом языке можно создавать приложения, способные работать на различных платформах. К сети Internet подключены компьютеры самых разных типов - PC, Macintosh, рабочие станции Sun и так далее. Даже в рамках компьютеров, созданных на базе процессоров Intel, существует несколько платформ, например, Microsoft Windows версии 3.1, Windows 95, Windows NT, OS/2, Solaris, различные разновидности операционной системы UNIX с графической оболочкой X Window. Между тем, создавая сервер 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 значительно упрощают разработку приложений, представляя в распоряжение программиста мощные средства решения распространенных задач. Поэтому программист может больше внимания уделить решению прикладных задач, а не таких, как, например, организация динамических массивов, взаимодействие с операционной системой или реализация элементов пользовательского интерфейса.


Java > Программирование на Java: подробное руководство > Введение в Java >
Программирование на Java
Инструментарий
Введение в Java
Инструментарий
Мобильность
Типы данных
Классы Java
Указатели
Массивы
Сборка мусора
Реализация классов

Назад Вперед

Первоначально средства разработки приложений и аплетов Java были созданы фирмой Sun Microsystems и до сих пор они пользуются популярностью. В сети Internet по адресу http://java.sun.com вы можете бесплатно получить набор Java Development Kit (JDK).

Пакетные средства

В JDK входят пакетные программы для компиляции исходных текстов приложений Java, виртуальная машина, программа автоматизированного создания документации по классам, справочник по классам Java и другие необходимые средства.

Интегрированные средства разработки

Для тех, кто привык пользоваться визуальными средствами разработки, доступны два других инструмента, созданных в Sun Microsystems. Это Java WorkShop 2.0 и Java Studio 1.0.

Интегрированная система разработки приложений Java WorkShop 2.0 содержит традиционные и визуальные средства программирования, отладчик, обширную справочную систему по классам и языку Java. С помощью Java WorkShop 2.0 вы можете создавать автономные приложения Java, аплеты, компоненты JavaBeans и собственные библиотеки классов.

На рис. 1 мы показали внешний вид главного окна приложения Java WorkShop 2.0.

pic01sm.gif (2791 bytes) Рис. 1. Главное окно приложения .

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Среди основных возможностей Java WorkShop 2.0 назовем синтаксическое выделение в окне редактирования, возможность удаленной отладки приложений Java, быстродействующий компилятор, а также способность работать на различных платформах.

Разработку элементов пользовательского интерфейса можно выполнять с помощью удобного средства визуального проектирования (рис. 2).

pic02sm.gif (3283 bytes) Рис. 2. Java WorkShop 2.0 позволяет разрабатывать пользовательский интерфес с помощью визуальных средств.

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Что же касается Java Studio 1.0, то эта система позволяет проектировать приложения вообще без программирования. Разработчик собирает приложения из готовых компонент, устанавливая между ними каналы передачи сообщений. Таким образом определяется логика работы приложения (рис. 3). Этот процесс чем-то напоминает сборку бытовой стереофонической системы из отдельных блоков, когда вы соединяете проводами входы и выходы усилителя, колонок, проигрывателя компакт-дисков и других устройств.

pic03sm.gif (2741 bytes) Рис. 3. Проектирование логики работы приложения.

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

В наборе компонент JavaBeans, доступных в Java Studio, есть компоненты, предназначенные для работы с ресурсами Internet, базами данных и таблицами, формами и так далее.

Проектирование пользовательского интерфейса в Java Studio, также как и в Java WorkShop, выполняется визуально (рис. 4).

Рис. 4. Визуальное проектирование пользовательского интерфейса.

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

pic04sm.gif (2356 bytes)

Подборку различных инструментальных средств, предназначенных для создания приложений Java, вы найдете по адресу http://www.sun.ru/download/download.html.

Браузеры

Для проверки работы аплетов вам следует установить браузер, способный работать с аплетами Java. Такая возможность есть во всех современных браузерах, поэтому вы можете выбрать любой из них. Лучше всего проверять работу создаваемых вами аплетов в различных браузерах. Это позволит вам обнаружить и решить проблемы несовместимости, прежде чем с ними столкнется пользователь.

Подключение к Internet

Заметим, что для запуска аплетов вам не нужно обязательно подключаться к Internet - вы можете встраивать аплеты в документы HTML, расположенные на локальном диске вашего компьютера и просматривать эти документы браузером просто как локальные файлы.

Автономные приложения Java работают под управлением специального интерпретатора (виртуальной машины Java), поэтому для их отладки вам также не потребуется сеть Internet.

Однако есть одно важное обстоятельство - аплеты, взаимодействующие с расширениями сервера Web, должны быть загружены именно с этого сервера. В противном случае их работа будет заблокирована по соображениям безопасности.

Если вы собираетесь проверять работу приложений и аплетов Java, взаимодействующих с сервером Web, вы можете воспользоваться собственным сервером в Internet или в корпоративной сети Intranet (если они у вас есть). Можно также установить сервер Web, входящий в комплект операционной системы Windows NT Workstation версии 4.0, или Personal Web Service для операционной системы Windows 95.

Документация и литература

На прилавках книжных магазинов вы можете найти несколько отечественных и переводных книг, посвященных программированию на языке Java. Большинство из них ориентировано на инструментарий JDK, созданный фирмой Sun, и содержат более или менее подробное описание классов Java.

Среди удачных назовем книгу Стефана Дэвиса с названием "Learn Java Now", которая может служить учебником по языку Java для тех, кто никогда не программировал на С и С++.

Среди переводных книг, которые можно встретить в продаже, отметим книгу Джона Родли "Создание JAVA-апплетов". Эта книга рассчитана на серьезных программистов, хорошо знающих язык программирования Java. Однако для тех, кто только начинает изучать язык Java, она может оказаться слишком сложной.

Другая книга, заслуживающая внимание, это книга Криса Джамса с названием "Java". После небольшого введения, рассчитанного на начинающих, в этой книге приводится описание более чем дюжины достаточно интересных аплетов с исходными текстами и комментариями.

Через сеть Internet вам доступны не только бесплатные средства разработки приложений и аплетов Java, но и грандиозные запасы документации и примеров программ.

В качестве отправной точки для поиска вы можете выбрать сервер разработчика этого языка - фирмы Sun Microsystems, расположенный по адресу http://www.sun.com. Помимо документации и примеров программ на Java, здесь вы найдете ссылки на другие ресурсы, посвященные этому языку программирования. Попробуйте также воспользоваться поисковыми серверами, такими как Yahoo! и Alta Vista, указав в качестве ключевого слово "Java".

Обращаем ваше внимание на cловарь Java-терминов, подготовленный Sun Microsystems специально для российских разработчиков приложений Java.


Мобильность
Введение в Java
Инструментарий
Мобильность
Типы данных
Классы Java
Указатели
Массивы
Сборка мусора
Реализация классов

Мобильность Java

Назад Вперед

В свое время вы слышали, что язык программирования С является мобильным. Это нужно понимать в том смысле, что имеется принципиальная возможность переноса программ C на различные платформы.

Однако следует отметить, что создание приложений, действительно работающих на разных платформах - непростая задача. К сожалению, дело не ограничивается необходимостью перекомпиляции исходного текста программы для работы в другой среде. Много проблем возникает с несовместимостью программных интерфейсов различных операционных систем и графических оболочек, реализующих пользовательский интерфейс.

Вспомните хотя бы проблемы, связанные с переносом 16-разрядных приложений Windows в 32-разрядную среду Windows 95 и Windows NT. Даже если вы тщательно следовали всем рекомендациям, разрабатывая приложения так, чтобы они могли работать в будущих версиях Windows, едва ли вам удастся просто перекомпилировать исходные тексты, не изменив в них ни строчки. Ситуация еще больше ухудшается, если вам нужно, например, перенести исходные тексты приложения Windows в среду операционной системы OS/2 или в оболочку X-Windows операционной системы UNIX. А ведь есть еще другие компьютеры и рабочие станции!

Как нетрудно заметить, даже если стандартизовать язык программирования для всех платформ, проблемы совместимости с программным интерфейсом операционной системы значительно усложняют перенос программ на различные платформы. И, конечно, вы не можете мечтать о том, чтобы загрузочный модуль одной и той же программы мог работать без изменений в среде различных операционных систем и на различных платформах. Если программа подготовлена для процессора Intel, она ни за что не согласится работать на процессоре Alpha или каком-либо другом.

В результате создавая приложение, способное работать на различных платформах, вы вынуждены фактически делать несколько различных приложений и сопровождать их по отдельности.

На рис. 5 мы показали, как приложение, изначально разработанное для Windows NT, переносится на платформу Apple Macintosh.

pic05.gif (3440 bytes)

Рис. 5. Перенос приложения с платформы Windows NT на платформу Macintosh

Вначале программист готовит исходные тексты приложения для платформы Windows NT и отлаживает их там. Для получения загрузочного модуля исходные тексты компилируются и редактируются. Полученный в результате загрузочный модуль может работать на процессоре фирмы Intel в среде операционной системы Windows NT.

Для того чтобы перенести приложение в среду операционной системы компьютера Macintosh, программист вносит необходимые изменения в исходные тексты приложения. Эти изменения необходимы из-за различий в программном интерфейсе операционной системы Windows NT и операционной системы, установленной в Macintosh. Далее эти исходные тексты транслируются и редактируются, в результате чего получается загрузочный модуль, способный работать в среде Macintosh, но не способный работать в среде Windows NT.

Программа на языке Java компилируется в двоичный модуль, состоящий из команд виртуального процессора Java. Такой модуль содержит байт-код, предназначенный для выполнения Java-интерпретатором. На настоящий момент уже созданы первые модели физического процессора, способного выполнять этот байт-код, однако интерпретаторы Java имеются на всех основных компьютерных платформах. Разумеется, на каждой платформе используется свой интерпретатор, или, точнее говоря, свой виртуальный процессор Java.

Если ваше приложение Java (или аплет) должно работать на нескольких платформах, нет необходимости компилировать его исходные тексты несколько раз. Вы можете откомпилировать и отладить приложение Java на одной, наиболее удобной для вас платформе. В результате вы получите байт-код, пригодный для любой платформы, где есть виртуальный процессор Java.

Сказанное иллюстрируется на рис. 6.

pic06.gif (3169 bytes)

Рис. 6. Подготовка приложения Java для работы на разных платформах

Таким образом, приложение Java компилируется и отлаживается только один раз, что уже значительно лучше. Остается, правда, вопрос - как быть с программным интерфейсом операционной системы, который отличается для разных платформ?

Здесь, на наш взгляд, разработчиками Java предлагается достаточно неплохое решение. Приложение Java не обращается напрямую к интерфейсу операционной системы. Вместо этого оно пользуется готовыми стандартными библиотеками классов, содержащими все необходимое для организации пользовательского интерфейса, обращения к файлам, для работы в сети и так далее.

Внутренняя реализация библиотек классов, разумеется, зависит от платформы. Однако все загрузочные модули, реализующие возможности этих библиотек, поставляются в готовом виде вместе с виртуальной машиной Java, поэтому программисту не нужно об этом заботиться. Для операционной системы Windows, например, поставляются библиотеки динамической загрузки DLL, внутри которых запрятана вся функциональность стандартных классов Java.

Абстрагируясь от аппаратуры на уровне библиотек классов, программисты могут больше не заботиться о различиях в реализации программного интерфейса конкретных операционных систем. Это позволяет создавать по-настоящему мобильные приложения, не требующие при переносе на различные платформы перетрансляции и изменения исходного текста.

Еще одна проблема, возникающая при переносе программ, составленных на языке программирования С, заключается в том, что размер области памяти, занимаемой переменными стандартных типов, различный на разных платформах. Например, в среде операционной системы Windows версии 3.1 переменная типа int в программе, составленной на С, занимает 16 бит. В среде Windows NT этот размер составляет 32 бита.

Очевидно, что трудно составлять программу, не зная точно, сколько имеется бит в слове или в байте. При переносе программ на платформы с иной разрядностью могут возникать ошибки, которые трудно обнаружить.

В языке Java все базовые типы данных имеют фиксированную разрядность, которая не зависит от платформы. Поэтому программисты всегда знают размеры переменных в своей программе.


Типы данных
Введение в Java
Инструментарий
Мобильность
Типы данных
Классы Java
Указатели
Массивы
Сборка мусора
Реализация классов

Базовые типы данных

Назад Вперед

В языке 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
Инструментарий
Мобильность
Типы данных
Классы Java
Указатели
Массивы
Сборка мусора
Реализация классов

Библиотеки классов 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 не допускается перезагрузка (переопределение) операторов, для объектов класса String и объектов всех произошедших от него классов сделана встроенная перезагрузка операторов "+" и "+=". С помощью этих операторов можно выполнять слияние текстовых строк, например:

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).

pic07sm.gif (3435 bytes) Рис. 7. Сетевая игра Java Color Lines.

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Это сетевая версия известной игры 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, это то, что в языке 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

Назад Вперед

Для создания массива вы можете пользоваться квадратными скобками, расположив их справа от имени массива или от типа объектов, из которых составлен массив, например:

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
Указатели
Массивы
Сборка мусора
Реализация классов

Сборка мусора

Назад Вперед

Одна из интереснейших особенностей языка программирования Java и среды выполнения приложений Java заключается в наличии специального процесса сборки мусора, предназначенного для удаления ненужных объектов из памяти. Эта система избавляет программиста от необходимости внимательно следить за использованием памяти, освобождая ненужные более области явным образом.

Создавая объекты в Java, вы можете руководствоваться принципом "создай и забудь", так как система сборки мусора позаботится об удалении ваших объектов. Объект будет удален из памяти, как только на него не останется ни одной ссылки из других объектов.

Приоритет процесса сборки мусора очень низкий, поэтому "уборка" среды выполнения приложений Java не отнимает ресурсы у самих приложений.


Реализация классов
Введение в Java
Инструментарий
Мобильность
Типы данных
Классы Java
Указатели
Массивы
Сборка мусора
Реализация классов

Особенности реализации классов в Java

Назад Вперед

Если вы умеете программировать на языке С++, у вас не возникнет никаких проблем с программированием на Java, так как эти языки очень похожи. Однако есть и некоторые отличия, которые следует учитывать. Мы приведем краткое перечисление основных отличий.

Определение класса

Для создания классов вы можете использовать только ключевое слово class. Что же касается union, то это ключевое слово в Java не применяется.

В языке программирования С++ описание класса может быть отделено от его определения. Для Java это не так - описание класса недопустимо. Все методы должны быть определены внутри определения класса.

Недопустимо определение вложенных классов.

В Java также нет шаблонов. Вы можете создавать классы только на базе других классов.

Объект класса создается при помощи ключевого слова new, однако вы не можете удалить объект явным образом, так как ключевое слово delete языка программирования С++ в Java не используется.

При определении класса вы не можете указать деструктор. Функции удаления объектов Java из памяти выполняет система сборки мусора.

Внутри одного исходного файла вы можете определить только один общедоступный класс public.

Все классы в Java наследуются от класса Object, поэтому для любого объекта вы можете использовать методы этого класса.

Определение методов

Вы не можете определять методы вне тела класса, создавая таким образом глобальные функции. Нет также возможности определения вне класса глобальных данных. Тем не менее, внутри класса можно определять статические методы и поля (с помощью ключевого слова static), которые будут играть роль глобальных методов и данных.

Пользуясь ключевыми словами static и final, можно определять внутри классов глобальные константы.

Если в базовом классе метод определен с ключевым словом final, его нельзя переопределить в дочернем классе, созданном на базе данного метода.

Методы не могут быть определены как inline.

Методы Java могут создавать исключения, вызванные возникновением ошибок или других событий. Все исключения должны либо обрабатываться внутри метода, либо описываться в определении метода после ключевого слова throws.

Переопределение операторов

В языке С++ вы могли переопределить операторы, такие как +, -, ++ и так далее. Язык Java не допускает переопределение, что сделано для упрощения программирования. Тем не менее, операторы "+" и "+=" перегружены по умолчанию для выполнения операции слияния текстовых строк класса String.

Интерфейсы

Интерфейсы создаются при помощи ключевого слова interface таким же образом, что и классы. Однако в отличие от последних, интерфейсы являются аналогом абстрактных базовых классов без полей данных и предназначены только для определений набора методов для решения каких-либо задач, например, добавления компонент в контейнеры, организации списков, сортировки и так далее.

Вы можете создать свой класс на базе другого класса, указав при этом с помощью ключевого слова implements, что он реализует тот или иной интерфейс. При этом наряду с методами базового класса в созданном таким образом классе будут доступны методы, определенные в интерфейсе.

Ссылки на методы класса

Так как в Java нет указателей, нет возможности ссылаться на методы с помощью оператора ->. Для ссылки на метод класса используется только оператор "точка".

Оператор "::" также не определен в Java. Если вам необходимо вызвать метод из базового класса, следует использовать ключевое слово super.

Наследование

С помощью ключевого слова extends вы можете унаследовать один класс (дочерний) от другого (базового).

Множественное наследование не допускается. Таким образом, для каждого дочернего класса может быть только один базовый класс. При необходимости, однако, этот дочерний класс может реализовывать произвольное количество интерфейсов.

Для ссылки на методы базового класса вы должны использовать ключевое слово super.

При необходимости вы можете вызвать в первой исполняемой строке конструктора дочернего класса конструктор базового класса (опять же с помощью ключевого слова super).


Рис. 1. Главное окно приложения

Для возврата сделайте щелчок мышью по рисунку

Рис. 1. Главное окно приложения


Рис. 2. Визуальные средства разработки Java WorkShop

Для возврата сделайте щелчок мышью по рисунку

Рис. 2. Визуальные средства разработки Java WorkShop 2.0


Рис. 3. Проектирование логики работы приложения

Для возврата сделайте щелчок мышью по рисунку

Рис. 3. Проектирование логики работы приложения


Рис. 4. Визуальное проектирование пользовательского интерфейса

Для возврата сделайте щелчок мышью по рисунку

Рис. 4. Визуальное проектирование пользовательского интерфейса


Рис. 7. Сетевая игра Java Color Lines

Для возврата сделайте щелчок мышью по рисунку

Рис. 7. Сетевая игра Java Color Lines


Многопоточность
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Многопоточность

Назад Вперед

Наверное, сегодня уже нет необходимости объяснять, что такое многопоточность. Все современные операционные системы, такие как Windows 95, Windows NT, OS/2 или UNIX способны работать в многопоточном режиме, повышая общую производительность системы за счет эффективного распараллеливания выполняемых потоков. Пока один поток находится в состоянии ожидания, например, завершения операции обмена данными с медленным периферийным устройством, другой может продолжать выполнять свою работу.

Пользователи уже давно привыкли запускать параллельно несколько приложений для того чтобы делать несколько дел сразу. Пока одно из них занимается, например, печатью документа на принтере или приемом электронной почты из сети Internet, другое может пересчитывать электронную таблицу или выполнять другую полезную работу. При этом сами по себе запускаемые приложения могут работать в рамках одного потока - операционная система сама заботится о распределении времени между всеми запущенными приложениями.

Создавая приложения для операционной системы Windows на языках программирования С или С++, вы могли решать многие задачи, такие как анимация или работа в сети, и без использования многопоточности. Например, для анимации можно было обрабатывать сообщения соответствующим образом настроенного таймера.

Приложениям Java такая методика недоступна, так как в этой среде не предусмотрено способов периодического вызова каких-либо процедур. Поэтому для решения многих задач вам просто не обойтись без многопоточности.


Процессы, потоки и приоритеты
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Процессы, потоки и приоритеты

Назад Вперед

Прежде чем приступить к разговору о многопоточности, следует уточнить некоторые термины.

Обычно в любой многопоточной операционной системе выделяют такие объекты, как процессы и потоки. Между ними существует большая разница, которую следует четко себе представлять.

Процесс

Процесс (process) - это объект, который создается операционной системой, когда пользователь запускает приложение. Процессу выделяется отдельное адресное пространство, причем это пространство физически недоступно для других процессов. Процесс может работать с файлами или с каналами связи локальной или глобальной сети. Когда вы запускаете текстовый процессор или программу калькулятора, вы создаете новый процесс.

Поток

Для каждого процесса операционная система создает один главный поток (thread ), который является потоком выполняющихся по очереди команд центрального процессора. При необходимости главный поток может создавать другие потоки, пользуясь для этого программным интерфейсом операционной системы.

Все потоки, созданные процессом, выполняются в адресном пространстве этого процесса и имеют доступ к ресурсам процесса. Однако поток одного процесса не имеет никакого доступа к ресурсам потока другого процесса, так как они работают в разных адресных пространствах. При необходимости организации взаимодействия между процессами или потоками, принадлежащими разным процессам, следует пользоваться системными средствами, специально предназначенными для этого.

Приоритеты потоков в приложениях Java

Если процесс создал несколько потоков, то все они выполняются параллельно, причем время центрального процессора (или нескольких центральных процессоров в мультипроцессорных системах) распределяется между этими потоками.

Распределением времени центрального процессора занимается специальный модуль операционной системы - планировщик. Планировщик по очереди передает управление отдельным потокам, так что даже в однопроцессорной системе создается полная иллюзия параллельной работы запущенных потоков.

Распределение времени выполняется по прерываниям системного таймера. Поэтому каждому потоку дается определенный интервал времени, в течении которого он находится в активном состоянии.

Заметим, что распределение времени выполняется для потоков, а не для процессов. Потоки, созданные разными процессами, конкурируют между собой за получение процессорного времени.

Каким именно образом?

Приложения Java могут указывать три значения для приоритетов потоков. Это NORM_PRIORITY, MAX_PRIORITY и MIN_PRIORITY.

По умолчанию вновь созданный поток имеет нормальный приоритет NORM_PRIORITY. Если остальные потоки в системе имеют тот же самый приоритет, то все потоки пользуются процессорным времени на равных правах.

При необходимости вы можете повысить или понизить приоритет отдельных потоков, определив для них значение приоритета, соответственно, MAX_PRIORITY или MIN_PRIORITY. Потоки с повышенным приоритетом выполняются в первую очередь, а с пониженным - только при отсутствии готовых к выполнению потоков, имеющих нормальный или повышенный приоритет.


Реализация многопоточности в Java
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Реализация многопоточности в Java

Назад Вперед
Вы должны воспользоваться классом java.lang.Thread. В этом классе определены все методы, необходимые для создания потоков, управления их состоянием и синхронизации.

Как пользоваться классом Thread?

Есть две возможности.

  • Во-первых, вы можете создать свой дочерний класс на базе класса Thread. При этом вы должны переопределить метод run. Ваша реализация этого метода будет работать в рамках отдельного потока.
  • Во-вторых, ваш класс может реализовать интерфейс Runnable. При этом в рамках вашего класса необходимо определить метод run, который будет работать как отдельный поток.

Второй способ особенно удобен в тех случаях, когда ваш класс должен быть унаследован от какого-либо другого класса (например, от класса Applet) и при этом вам нужна многопоточность. Так как в языке программирования Java нет множественного наследования, невозможно создать класс, для которого в качестве родительского будут выступать классы Applet и Thread. В этом случае реализация интерфейса Runnable является единственным способом решения задачи.

Методы класса Thread

В классе Thread определены три поля, несколько конструкторов и большое количество методов, предназначенных для работы с потоками. Ниже мы привели краткое описание полей, конструкторов и методов.

С помощью конструкторов вы можете создавать потоки различными способами, указывая при необходимости для них имя и группу. Имя предназначено для идентификации потока и является необязательным атрибутом. Что же касается групп, то они предназначены для организации защиты потоков друг от друга в рамках одного приложения.

Методы класса Thread предоставляют все необходимые возможности для управления потоками, в том числе для их синхронизации.

Поля

Три статических поля предназначены для назначения приоритетов потокам.

  • NORM_PRIORITY

Нормальный

public final static int NORM_PRIORITY;
  • MAX_PRIORITY

Максимальный

public final static int MAX_PRIORITY;
  • MIN_PRIORITY

Минимальный

public final static int MIN_PRIORITY;

Конструкторы

Создание нового объекта Thread

public Thread();

Создвание нового объекта Thread с указанием объекта, для которого будет вызываться метод run

public Thread(Runnable target);

Аналогично предыдущему, но дополнительно задается имя нового объекта Thread

public Thread(Runnable target, String name);

Создание объекта Thread с указанием его имени

public Thread(String name);

Создание нового объекта Thread с указанием группы потока и объекта, для которого вызывается метод run

public Thread(ThreadGroup group,
  Runnable target);

Аналогично предыдущему, но дополнительно задается имя нового объекта Thread

public Thread(ThreadGroup group,
  Runnable target, String name);

Создание нового объекта Thread с указанием группы потока и имени объекта

public Thread(ThreadGroup group, String name);

Методы

  • activeCount

Текущее количество активных потоков в группе, к которой принадлежит поток

public static int activeCount();
  • checkAccess

Текущему потоку разрешается изменять объект Thread

public void checkAccesss();
  • countStackFrames

Определение количества фреймов в стеке

public int countStackFrames();
  • currentThread

Определение текущего работающего потока

public static Thread currentThread();
  • destroy

Принудительное завершение работы потока

public void destroy();
  • dumpStack

Вывод текущего содержимого стека для отладки

public static void dumpStack();
  • enumerate

Получение всех объектов Tread данной группы

public static int enumerate(Thread  tarray[]);
  • getName

Определение имени потока

public final String getName();
  • getPriority

Определение текущего приоритета потока

public final int getPriority();
  • getThreadGroup

Определение группы, к которой принадлежит поток

public final ThreadGroup getThreadGroup();
  • interrupt

Прерывание потока

public void interrupt();
  • interrupted

Определение, является ли поток прерванным

public static boolean interrupted();
  • isAlive

Определение, выполняется поток или нет

public final boolean isAlive();
  • isDaemon

Определение, является ли поток демоном

public final boolean isDaemon();
  • isInterrupted

Определение, является ли поток прерванным

public boolean isInterrupted();
  • join

Ожидание завершения потока

public final void join();

Ожидание завершения потока в течение заданного времени. Время задается в миллисекундах

public final void join(long millis);

Ожидание завершения потока в течение заданного времени. Время задается в миллисекундах и наносекундах

public final void join(long  millis, int  nanos);
  • resume

Запуск временно приостановленного потока

public final void resume();
  • run

Метод вызывается в том случае, если поток был создан как объект с интерфейсом Runnable

public void run();
  • setDaemon

Установка для потока режима демона

public final void setDaemon(boolean on);
  • setName

Устаовка имени потока

public final void setName(String name);
  • setPriority

Установка приоритета потока

public final void setPriority(int newPriority);
  • sleep

Задержка потока на заднное время. Время задается в миллисекундах и наносекундах

public static void sleep(long millis);

Задержка потока на заднное время. Время задается в миллисекундах и наносекундах

public static void sleep(long millis, int nanos);
  • start

Запуск потока на выполнение

public void start();
  • stop

Остановка выполнения потока

public final void stop();

Аварийная остановка выполнения потока с заданным исключением

public final void stop(Throwable obj);
  • suspend

Приостановка потока

public final void suspend();
  • toString

Строка, представляющая объект-поток

public String toString();
  • yield

Приостановка текущего потока для того чтобы управление было передано другому потоку

public static void yield();

Создание дочернего класса на базе класса Thread

Рассмотрим первый способ реализации многопоточности, основанный на наследовании от класса Thread. При использовании этого способа вы определяете для потока отдельный класс, например, так:

class DrawRectangles extends Thread
{
  . . .
  public void run()
  {
    . . .
  }
}

Здесь определен класс DrawRectangles, который является дочерним по отношению к классу Thread.

Обратите внимание на метод run. Создавая свой класс на базе класса Thread, вы должны всегда определять этот метод, который и будет выполняться в рамках отдельного потока.

Заметим, что метод run не вызывается напрямую никакими другими методами. Он получает управление при запуске потока методом start.

Как это происходит?

Рассмотрим процедуру запуска потока на примере некоторого класса DrawRectangles.

Вначале ваше приложение должно создать объект класса Thread:

public class MultiTask2 extends Applet
{
  Thread m_DrawRectThread = null;
  . . .
  public void start()
  {
    if (m_DrawRectThread == null)
    {
      m_DrawRectThread = new DrawRectangles(this);
      m_DrawRectThread.start();
    }
  }
}

Создание объекта выполняется оператором new в методе start, который получает управление, когда пользователь открывает документ HTML с аплетом. Сразу после создания поток запускается на выполнение, для чего вызывается метод start.

Что касается метода run, то если поток используется для выполнения какой либо периодической работы, то этот метод содержит внутри себя бесконечный цикл. Когда цикл завершается и метод run возвращает управление, поток прекращает свою работу нормальным, не аварийным образом. Для аварийного завершения потока можно использовать метод interrupt.

Остановка работающего потока выполняется методом stop. Обычно остановка всех работающих потоков, созданных аплетом, выполняется методом stop класса аплета:

public void stop()
{
  if (m_DrawRectThread != null)
  {
    m_DrawRectThread.stop();
    m_DrawRectThread = null;
  }
}

Напомним, что этот метод вызывается, когда пользователь покидает страницу сервера Web, содержащую аплет.

Реализация интерфейса Runnable

Описанный выше способ создания потоков как объектов класса Thread или унаследованных от него классов кажется достаточнао естественным. Однако этот способ не единственный. Если вам нужно создать только один поток, работающую одновременно с кодом аплета, проще выбрать второй способ с использованием интерфейса Runnable.

Идея заключается в том, что основной класс аплета, который является дочерним по отношению к классу Applet, дополнительно реализует интерфейс Runnable, как это показано ниже:

public class MultiTask extends
  Applet implements Runnable
{
  Thread m_MultiTask = null;
  . . .
  public void run()
  {
    . . .
  }

  public void start()
  {
    if (m_MultiTask == null)
    {
      m_MultiTask = new Thread(this);
      m_MultiTask.start();
    }
  }

  public void stop()
  {
    if (m_MultiTask != null)
    {
      m_MultiTask.stop();
      m_MultiTask = null;
    }
  }
}

Внутри класса необходимо определить метод run, который будет выполняться в рамках отдельного потока. При этом можно считать, что код аплета и код метода run работают одновременно как разные потоки.

Для создания потока используется оператор new. Поток создается как объект класса Thread, причем конструктору передается ссылка на класс аплета:

m_MultiTask = new Thread(this);

При этом, когда поток запустится, управление получит метод run, определенный в классе аплета.

Как запустить поток?

Запуск выполняется, как и раньше, методом start. Обычно поток запускается из метода start аплета, когда пользователь отображает страницу сервера Web, содержащую аплет. Остановка потока выполняется методом stop.


Многопоточность и анимация
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Применение многопоточности для анимации

Назад Вперед

Одно из наиболее распространенных применений аплетов - это создание анимационных эффектов типа бегущей строки, мерцающих огней или аналогичных, привлекающих внимание пользователя. Для того чтобы достичь такого эффекта, необходим какой либо механизм, позволяющий выполнять перерисовку всего окна аплета или его части периодически с заданным временным интервалом.

Работа аплетов, так же как и обычных приложений операционной системы Windows, основана на обработке событий. Для классического приложения Windows событие - это приход сообщения в функцию окна. Основной класс аплета обрабатывает события, переопределяя те или иные методы базового класса Applet.

Проблема с периодическим обновлением окна аплета возникает из-за того, что в языке Java не предусмотрено никакого механизма для создания генератора событий, способного вызывать какой-либо метод класса аплета с заданным интервалом времени. Вы не можете поступить так, как поступали в этой ситуации, разрабатывая обычные приложения Windows - создать таймер и организовать обработку периодически поступающих от него сообщений WM_TIMER.

Напомним, что перерисовка окна аплета выполняется методом paint, который вызывается виртуальной машиной Java асинхронно по отношению к выполнению другого кода аплета.

Можно ли воспользоваться методом paint для периодической перерисовки окна аплета, организовав в нем, например, бесконечный цикл с задержкой?

К сожалению, так поступать ни в коем случае нельзя. Метод paint после перерисовки окна аплета должен сразу возвратить управление, иначе работа аплета будет заблокирована.

Единственный выход из создавшейся ситуации - создание потока (или нескльких потоков), которые будут выполнять рисование в окне аплета асинхронно по отношению к работе кода аплета. Например, вы можете создать поток, который периодически обновляет окно аплета, вызывая для этого метод repaint, или рисовать из потока непосредственно в окне аплета, получив предварительно для этого окна контекст отображения.


Синхронизация потоков
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Синхронизация потоков

Назад Вперед

Многопоточный режим работы открывает новые возможности для программистов, однако за эти возможности приходится расплачиваться усложнением процесса проектирования приложения и отладки. Основная трудность, с которой сталкиваются программисты, никогда не создававшие ранее многопоточные приложения, это синхронизация одновременно работающих потоков.

Для чего и когда она нужна?

Однопоточная программа, такая, например, как программа MS-DOS, при запуске получает в монопольное распоряжение все ресурсы компьютера. Так как в однопоточной системе существует только один процесс, он использует эти ресурсы в той последовательности, которая соответствует логике работы программы. Процессы и потоки, работающие одновременно в многопоточной системе, могут пытаться обращаться одновременно к одним и тем же ресурсам, что может привести к неправильной работе приложений.

Поясним это на простом примере.

Пусть мы создаем программу, выполняющую операции с банковским счетом. Операция снятия некоторой суммы денег со счета может происходить в следующей последовательности:

  • на первом шаге проверяется общая сумма денег, которая хранится на счету;
  • если общая сумма равна или превышает размер снимаемой суммы денег, общая сумма уменьшается на необходимую величину;
  • значение остатка записывается на текущий счет.

Если операция уменьшения текущего счета выполняется в однопоточной системе, то никаких проблем не возникнет. Однако представим себе, что два процесса пытаются одновременно выполнить только что описанную операцию с одним и тем же счетом. Пусть при этом на счету находится 5 млн. долларов, а оба процесса пытаются снять с него по 3 млн. долларов.

Допустим, события разворачиваются следующим образом:

  • первый процесс проверяет состояние текущего счета и убеждается, что на нем хранится 5 млн. долларов;
  • второй процесс проверяет состояние текущего счета и также убеждается, что на нем хранится 5 млн. долларов;
  • первый процесс уменьшает счет на 3 млн. долларов и записывает остаток (2 млн. долларов) на текущий счет;
  • второй процесс выполняет ту же самую операцию, так как после проверки считает, что на счету по-прежнему хранится 5 млн. долларов.

В результате получилось, что со счета, на котором находилось 5 млн. долларов, было снято 6 млн. долларов, и при этом там осталось еще 2 млн. долларов! Итого - банку нанесен ущерб в 3 млн. долларов.

Как же составить программу уменьшения счета, чтобы она не позволяла вытворять подобное?

Очень просто - на время выполнения операций над счетом одним процессом необходимо запретить доступ к этому счету со стороны других процессов. В этом случае сценарий работы программы должен быть следующим:

  • процесс блокирует счет для выполнения операций другими процессами, получая его в монопольное владение;
  • процесс проводит процедуру уменьшения счета и записывает на текущий счет новое значение остатка;
  • процесс разблокирует счет, разрешая другим процессам выполнение операций.

Когда первый процесс блокирует счет, он становится недоступен другим процессам. Если второй процесс также попытается заблокировать этот же счет, он будет переведен в состояние ожидания. Когда первый процесс уменьшит счет и на нем останется 2 млн. долларов, второй процесс будет разблокирован. Он проверит остаток, убедится, что сумма недостаточна и не будет проводить операцию.

Таким образом, в многопоточной среде необходима синхронизация потоков при обращении к критическим ресурсам. Если над такими ресурсами будут выполняться операции в неправильной последовательности, это приведет к возникновению трудно обнаруживаемых ошибок.

В языке программирования Java предусмотрено несколько средств для синхронизации потоков, которые мы сейчас рассмотрим.

Синхронизация методов

Возможность синхронизации как бы встроена в каждый объект, создаваемый приложением Java. Для этого объекты снабжаются защелками, которые могут быть использованы для блокировки потоков, обращающихся к этим объектам.

Чтобы воспользоваться защелками, вы можете объявить соответствующий метод как synchronized, сделав его синхронизированным:

public synchronized void decrement()
{
  . . .
}

При вызове синхронизированного метода соответствующий ему объект (в котором он определен) блокируется для использования другими синхронизированными методами. В результате предотвращается одновременная запись двумя методами значений в область памяти, принадлежащую данному объекту.

Использование синхронизированных методов - достаточно простой способ синхронизации потоков, обращающихся к общим критическим ресурсам, наподобие описанного выше банковского счета.

Заметим, что не обязательно синхронизовать весь метод - можно выполнить синхронизацию только критичного фрагмента кода.

. . .
synchronized(Account)
{
  if(Account.check(3000000))
     Account.decrement(3000000);
}
. . .

Здесь синхронизация выполняется для объекта Account.

Блокировка потока

Синхронизированный поток, определенный как метод типа synchronized, может переходить в заблокированное состояние автоматически при попытке обращения к ресурсу, занятому другим синхронизированным методом, либо при выполнении некоторых операций ввода или вывода. Однако в ряде случаев полезно иметь более тонкие средства синхронизации, допускающие явное использование по запросу приложения.

Блокировка на заданный период времени

С помощью метода sleep можно заблокировать поток на заданный период времени:

try
{
  Thread.sleep(500);
}
catch (InterruptedException ee)
{
  . . .
}

В данном примере работа потока Thread приостанавливается на 500 миллисекунд. Заметим, что во время ожидания приостановленный поток не отнимает ресурсы процессора.

Так как метод sleep может создавать исключение InterruptedException, необходимо предусмотреть его обработку. Для этого мы использовали операторы try и catch.

Временная приостановка и возобновление работы

Методы suspend и resume позволяют, соответственно, временно приостанавливать и возобновлять работу потока.

В следующем фрагменте кода поток m_Rectangles приостанавливает свою работу, когда курсор мыши оказывается над окном аплета:

public boolean mouseEnter(Event evt,
   int x, int y)
{
  if (m_Rectangles != null)
  {
    m_Rectangles.suspend();
  }
  return true;
}

Работа потока возобновляется, когда курсор мыши покидает окно аплета:

public boolean mouseExit(Event evt,
   int x, int y)
{
  if (m_Rectangles != null)
  {
    m_Rectangles.resume();
  }
  return true;
}

Ожидание извещения

Если вам нужно организовать взаимодействие потоков таким образом, чтобы один поток управлял работой другого или других потоков, вы можете воспользоваться методами wait, notify и notifyAll, определенными в классе Object.

Метод wait может использоваться либо с параметром, либо без параметра. Этот метод переводит поток в состояние ожидания, в котором он будет находиться до тех пор, пока для потока не будет вызван извещающий метод notify, notifyAll, или пока не истечет период времени, указанный в параметре метода wait.

Как пользоваться методами wait, notify и notifyAll?

Метод, который будет переводиться в состояние ожидания, должен быть синхронизированным, то есть его следует описать как synchronized:

public synchronized void run()
{
  while (true)
  {
    . . .
    try
    {
      this.wait();
    }
    catch (InterruptedException e)
    {
    }
  }
}

В этом примере внутри метода run определен цикл, вызывающий метод wait без параметров. Каждый раз при очередном проходе цикла метод run переводится в состояние ожидания до тех пор, пока другой поток не выполнит извещение с помощью метода notify.

Ниже мы привели пример потока, вызывающией метод notify:

public void run()
{
  while (true)
  {
    try
    {
      Thread.sleep(30);
    }
    catch (InterruptedException e)
    {
    }

    synchronized(STask)
    {
      STask.notify();
    }
  }
}

Этот поток реализован в рамках отдельного класса, конструктору которого передается ссылка на поток, вызывающую метод wait. Эта ссылка хранится в поле STask.

Обратите внимание, что хотя сам метод run не синхронизированный, вызов метода notify выполняется в синхронизированном режиме. В качестве объекта синхронизации выступает поток, для которого вызывается метод notify.

Ожидание завершения потока

С помощью метода join вы можете выполнять ожидание завершения работы потока, для которой этот метод вызван.

Существует три определения метода join:

public final void join();
public final void join(long millis);
public final void join(long millis,
   int nanos);

Первый из них выполняет ожидание без ограничения во времени, для второго ожидание будет прервано принудительно через millis миллисекунд, а для третьего - через millis миллисекунд и nanos наносекунд. Учтите, что реально вы не сможете указывать время с точностью до наносекунд, так как дискретность системного таймера компьютера намного больше.


Потоки-демоны
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Потоки-демоны

Назад Вперед

Вызвав для потока метод setDaemon, вы превращаете обычную поток в поток-демон. Такой поток работает в фоновом режиме независимо от породившего его потока. Если поток-демон создает другие потоки, то они также станут получат статус потока-демона.

Заметим, что метод setDaemon необходимо вызывать после создания потока, но до момента его запуска, то есть перед вызовом метода start.

С помощью метода isDaemon вы можете проверить, является поток демоном, или нет.


Аплет Rectangles
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Аплет Rectangles

Назад Вперед

В качестве примера многопоточного приложения мы приведем аплет Rectangles (рис. 1). Он создает три потока. Первый поток рисует в окне аплета прямоугольники случайного размера и цвета, второй - эллипсы, а третий управляет потоком рисования эллипсов.

pic01.gif (7162 bytes)

Рис. 1. Окно аплета Rectangles

Расположение прямоугольников и эллипсов также выбирается случайно.


Исходные тексты
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Исходные тексты аплета Rectangles

Назад Вперед

Исходные тексты аплета Rectangles приведены в листинге 1.

Листинг 1. Файл Rectangles,java

import java.applet.*;
import java.awt.*;
public class Rectangles extends Applet
{
  DrawRectangles m_DrawRectThread = null;
  DrawEllipse m_DrawEllipseThread = null;
  NotifyTask m_NotifyTaskThread = null
  public String getAppletInfo()
  {
    return "Name: Rectangles";
  }
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension = getSize();
    g.setColor(Color.yellow);
    g.fillRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
  }
  public void start()
  {
    if (m_DrawRectThread == null)
    {
      m_DrawRectThread =
        new DrawRectangles(this);
      m_DrawRectThread.start();
    }
    if (m_DrawEllipseThread == null)
    {
      m_DrawEllipseThread =
        new DrawEllipse(this);
      m_DrawEllipseThread.start();
    }
    if (m_NotifyTaskThread == null)
    {
      m_NotifyTaskThread =
        new NotifyTask(m_DrawEllipseThread);
      m_NotifyTaskThread.start();
    }
  }

  public void stop()
  {
    if (m_DrawRectThread != null)
    {
      m_DrawRectThread.stop();
      m_DrawRectThread = null;
    }
    if (m_DrawEllipseThread == null)
    {
      m_DrawEllipseThread.stop();
      m_DrawEllipseThread = null;
    }
    if (m_NotifyTaskThread != null)
    {
      m_NotifyTaskThread.stop();
      m_NotifyTaskThread = null;
    }
  }
}
class DrawRectangles extends Thread
{
  Graphics g;
  Dimension dimAppWndDimension;
  public DrawRectangles(Applet Appl)
  {
    g = Appl.getGraphics();
    dimAppWndDimension = Appl.getSize();
  }
  public void run()
  {
    while (true)
    {
      int x, y, width, height;
      int rColor, gColor, bColor;
      x =      (int)(dimAppWndDimension.width
            * Math.random());
      y =      (int)(dimAppWndDimension.height
            * Math.random());
      width  = (int)(dimAppWndDimension.width
            * Math.random()) / 2;
      height = (int)(dimAppWndDimension.height
            * Math.random()) / 2;
      rColor = (int)(255 * Math.random());
      gColor = (int)(255 * Math.random());
      bColor = (int)(255 * Math.random());
      g.setColor(new Color(rColor,
        gColor, bColor));
      g.fillRect(x, y, width, height);
      try
      {
    Thread.sleep(50);
      }
      catch (InterruptedException e)
      {
    stop();
      }
    }
  }
}
class DrawEllipse extends Thread
{
  Graphics g;
  Dimension dimAppWndDimension;
  public DrawEllipse(Applet Appl)
  {
    g = Appl.getGraphics();
    dimAppWndDimension = Appl.getSize();
  }
  public synchronized void run()
  {
    while (true)
    {
      int x, y, width, height;
      int rColor, gColor, bColor;
      x =      (int)(dimAppWndDimension.width
          * Math.random());
      y =      (int)(dimAppWndDimension.height
          * Math.random());
      width  = (int)(dimAppWndDimension.width
          * Math.random()) / 2;
      height = (int)(dimAppWndDimension.height
          * Math.random()) / 2;
      rColor = (int)(255 * Math.random());
      gColor = (int)(255 * Math.random());
      bColor = (int)(255 * Math.random());
      g.setColor(new Color(rColor,
         gColor, bColor));
      g.fillOval(x, y, width, height);
      try
      {
    this.wait();
      }
      catch (InterruptedException e)
      {
      }
    }
  }
}
class NotifyTask extends Thread
{
  Thread STask;
  public NotifyTask(Thread SynchroTask)
  {
    STask = SynchroTask;
  }
  public void run()
  {
    while (true)
    {
      try
      {
    Thread.sleep(30);
      }
      catch (InterruptedException e)
      {
      }
      synchronized(STask)
      {
        STask.notify();
      }
    }
  }
}


Описание текстов
Многопоточность
Процессы, потоки и приоритеты
Реализация многопоточности в Java
Многопоточность и анимация
Синхронизация потоков
Потоки-демоны
Аплет Rectangles
Исходные тексты
Описание текстов

Описание исходных текстов аплета Rectangles

Назад Вперед

В этом приложении мы создаем на базе класса Thread три класса. Первый из них предназначен для создания потока рисования прямоугольников, второй - для создания потока рисования закрашенных эллипсов, а третий - для управления потоком рисования эллипсов.

Что же касается основного класса аплета, то он унаследован, как обычно, от класса Applet и не реализует интерфейс Runnable:

public class Rectangles extends Applet
{
  . . .
}

Поля класса Rectangles

В классе Rectangles мы определили три поля с именами m_DrawRectThread, m_DrawEllipseThread и m_NotifyTaskThread:

DrawRectangles m_DrawRectThread = null;
DrawEllipse m_DrawEllipseThread = null;
NotifyTask m_NotifyTaskThread = null

Эти поля являются ссылками на классы, соответственно DrawRectangles, DrawEllipse и NotifyTask . Первый из них создан для рисования прямоугольников, второй - эллипсов, а третий - для управления потоком рисования эллипсов.

Указанные поля инициализируются занчением null, что соответствует неработающим или несозданным задачам.

Метод start класса Rectangles

Этот метод последовательно создает три потока и запускает их на выполнение:

if(m_DrawRectThread == null)
{
  m_DrawRectThread =
    new DrawRectangles(this);
  m_DrawRectThread.start();
}
if(m_DrawEllipseThread == null)
{
  m_DrawEllipseThread =
    new DrawEllipse(this);
  m_DrawEllipseThread.start();
}
if(m_NotifyTaskThread == null)
{
  m_NotifyTaskThread =
    new NotifyTask(m_DrawEllipseThread);
  m_NotifyTaskThread.start();
}

В качестве параметра конструкторам классов DrawRectangles и DrawEllipse мы передаем ссылку на аплет Rectangles. Эта ссылка будет нужна для получения контекста отображения и рисования геометрических фигур.

Поток класса NotifyTask будет управлять работой потока DrawEllipse, поэтому мы передаем его конструктору ссылку на соответствующий объект m_DrawEllipseThread.

Метод stop класса Rectangles

Когда пользователь покидает страницу сервера Web с аплетом, метод stop класса Rectangles последовательно останавливает gjnjrb рисования прямоугольников и эллипсов, а также управляющий поток:

if(m_DrawRectThread != null)
{
  m_DrawRectThread.stop();
  m_DrawRectThread = null;
}
if(m_DrawEllipseThread == null)
{
  m_DrawEllipseThread.stop();
  m_DrawEllipseThread = null;
}
if(m_NotifyTaskThread != null)
{
  m_NotifyTaskThread.stop();
  m_NotifyTaskThread = null;
}

Поля класса DrawRectangles

Класс DrawRectangles определен для потока рисования прямоугольников:

class DrawRectangles extends Thread
{
  . . .
}

В поле g класа хранится контекст отображения окна аплета, а в поле dimAppWndDimension - размеры этого окна:

Graphics g;
Dimension dimAppWndDimension;

Значения этих полей определяются конструктором класса по ссылке на главный класс аплета.

Конструктор класса DrawRectangles

В качестве параметра конструктору передается ссылка на класс аплета. Конструктор использует эту ссылку для получения и сохранения в полях класса контекста отображения и размеров окна аплета:

public DrawRectangles(Applet Appl)
{
  g = Appl.getGraphics();
  dimAppWndDimension = Appl.getSize();
}

Метод run класса DrawRectangles

Программный код метода run работает в рамках отдельного потока. Он рисует в окне аплета закрашенные прямоугольники. Прямоугольники имеют случайные координаты, расположение и цвет.

Для того чтобы рисовать, необходимо получить контекст отображения. Этот контекст был получен конструктором класса DrawRectangles и может быть использован методом run.

Вооружившись контекстом отображения и размерами окна аплета, поток входит в бесконечный цикл рисования прямоугольников.

В качестве генератора случайных чисел мы используем метод random из класса Math, который при каждом вызове возвращает новое случайное число типа double, лежащее в диапазоне значений от 0.0 до 1.0.

Координаты по осям X и Y рисуемого прямоугольника определяются простым умножением случайного числа, полученного от метода random, соответственно, на ширину и высоту окна аплета:

x = (int)(dimAppWndDimension.width
  * Math.random());
y = (int)(dimAppWndDimension.height
  * Math.random());

Аналогично определяются размеры прямоугольника, однако чтобы прямоугольники не были слишком крупными, мы делим полученные значения на 2:

width  = (int)(dimAppWndDimension.width
  * Math.random()) / 2;
height = (int)(dimAppWndDimension.height
  * Math.random()) / 2;

Так как случайное число имеет тип double, в обоих случаях мы выполняем явное преобразование результата вычислений к типу int.

Для случайного выбора цвета прямоугольника мы вычисляем отдельные цветовые компоненты, умножая значение, полученное от метода random, на число 255:

rColor = (int)(255 * Math.random());
gColor = (int)(255 * Math.random());
bColor = (int)(255 * Math.random());

Полученные значения цветовых компонент используются в конструкторе Color для получения цвета. Этот цвет устанавливается в контексте отображения методом setColor:

g.setColor(new Color(rColor,
  gColor, bColor));

Теперь все готово для рисования прямоугольника, которое мы выполняем при помощи метода fillRect:

g.fillRect(x, y, width, height);

После рисования прямоугольника метод run задерживает свою работу на 50 миллисекунд, вызывая метод sleep:

try
{
  Thread.sleep(50);
}
catch (InterruptedException e)
{
  stop();
}

Для обработки исключения InterruptedException, которое может возникнуть во время работы этого метода, мы предусмотрели блок try - catch. При возникновении указанного исключения работа потока останавливается вызовом метода stop.

Метод run класса DrawEllipse

Класс DrawEllipse очень похож на только что рассмотренный класс DrawRectangles. Отличие есть только в финальном фрагменте метода run, который мы и рассмотрим.

Вместо задержки на 50 миллисекунд метод run из класса DrawEllipse переходит в состояние ожидания извещения, вызывая метод wait:

try
{
  this.wait();
}
catch (InterruptedException e)
{
}

Это извещение создается управляющим потоком класса NotifyTask, к описанию которого мы переходим.

Поля класса NotifyTask

В классе NotifyTask мы определили одно поле STask класса Thread. Это поле которое хранит ссылку на поток, работой которого управляет данный класс:

class NotifyTask extends Thread
{
  Thread STask;
   . . .
}

Конструктор класса NotifyTask

Конструктор класса NotifyTask записывает в поле STask ссылку на задачу рисования эллипсов:

public NotifyTask(Thread SynchroTask)
{
  STask = SynchroTask;
}

Метод run класса NotifyTask

Метод run класса NotifyTask периодически разблокирует поток рисования эллипсов, вызывая для этого метод notify в цилке с задержкой 30 миллисекунд. Обращение к объекту STask, который хранит ссылку на поток рисования эллипсов, выполняется с использованием синхронизации:

public void run()
{
  while (true)
  {
    try
    {
      Thread.sleep(30);
    }
    catch (InterruptedException e)
    {
    }
    synchronized(STask)
    {
      STask.notify();
    }
  }
}


Работа с файлами
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Работа с файлами

Назад Вперед

Библиотека классов языка программирования Java содержит многочисленные средства, предназначенные для работы с файлами. И хотя аплеты не имеют доступа к локальным файлам, расположенным на компьютере пользователя, они могут обращаться к файлам, которые находятся в каталоге сервера Web. Автономные приложения Java могут работать как с локальными, так и с удаленными файлами (через сеть Internet или Intranet).

В любом случае, будете ли вы создавать автономные приложения Java или аплеты, взаимодействующие с сервером Web через сеть, вы должны познакомиться с классами, предназначенными для организации ввода и вывода.


Классы потоков
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Классы Java для работы с потоками

Назад Вперед

Программист, создающий автономное приложение Java, может работать с потоками нескольких типов:

  • стандартные потоки ввода и вывода;
  • потоки, связанные с локальными файлами;
  • потоки, связанные с файлами в оперативной памяти;
  • потоки, связанные с удаленными файлами

Рассмотрим кратко классы, связанные с потоками.

Стандартные потоки

Для работы со стандартными потоками в классе System имеется три статических объекта: System.in, System.out и System.err. По своему назначению эти потоки больше всего напоминают стандартные потоки ввода, вывода и вывода сообщений об ошибках операционной системы MS-DOS.

Поток System.in связан с клавиатурой, поток System.out и System.err - с консолью приложения Java.

Базовые классы для работы с файлами и потоками

Количество классов, созданных для работы с файлами, достаточно велико, чтобы привести начинающего программиста в растерянность. Прежде чем мы займемся конкретными классами и приведем примеры приложений, работающих с потоками и файлами, рассмотрим иерархию классов, предназначенных для орагнизации ввода и вывода.

Все основные классы, интересующие нас в этой главе, произошли от класса Object (рис. 1).

pic01.gif (2917 bytes)

Рис. 1. Основные классы для работы с файлами и потоками

Класс InputStream

Класс InputStream является базовым для большого количества классов, на основе которых создаются потоки ввода. Именно производные классы применяются программистами, так как в них имеются намного более мощные методы, чем в классе InputStream. Эти методы позволяют работать с потоком ввода не на уровне отдельных байт, а на уровне объектов различных классов, например, класса String и других.

Класс OutputStream

Аналогично, класс OutputStream служит в качестве базового для различных классов, имеющих отношение к потокам вывода.

Класс RandomAccesFile

С помощью класса RandomAccesFile можно организовать работу с файлами в режиме прямого доступа, когда программа указывает смещение и размер блока данных, над которым выполняется операция ввода или вывода. Заметим, кстати, что классы InputStream и OutputStream также можно использовать для обращения к файлам в режиме прямого доступа.

Класс File

Класс File предназначен для работы с оглавлениями каталогов. С помощью этого класса можно получить список файлов и каталогов, расположенных в заданном каталоге, создать или удалить каталог, переименовать файл или каталог, а также выполнить некоторые другие операции.

Класс FileDescriptor

C помощью класса FileDescriptor вы можете проверить идентификатор открытого файла.

Класс StreamTokenizer

Очень удобен класс StreamTokenizer. Он позволяет организовать выделение из входного потока данных элементов, отделенных друг от друга заданными разделителями, такими, например, как запятая, пробел, символы возврата каретки и перевода строки.

Производные от класса InputStream

От класса InputStream производится много других классов, как это показано на рис. 2.

pic02.gif (5262 bytes)

Рис. 2. Классы, производные от класса InputStream

Класс FilterInputStream

Класс FilterInputStream, который происходит непосредственно от класса InputStream, является абстрактным классом, на базе которого созданы классы BufferedInputStream, DataInputStream, LineNumberInputStream и PushBackInputStream. Непосредственно класс FilterInputStream не используется в приложениях Java, так как, во-первых, он является абстрактным и предназначен для переопределения методов базового класса InputStream, а во-вторых, наиболее полезные методы для работы с потоками ввода имеются в классах, созданных на базе класса FilterInputStream.

Класс BufferedInputStream

Буферизация операций ввода и вывода в большинстве случаев значительно ускоряет работу приложений, так как при ее использовании сокращается количество обращений к системе для обмена данными с внешними устройствами.

Класс BufferedInputStream может быть использован приложениями Java для организации буферизованных потоков ввода. Заметим, что конструкторы этого класса в качестве параметра получают ссылку на объект класса InputStream. Таким образом, вы не можете просто создать объект класса BufferedInputStream, не создав перед этим объекта класса InputStream. Подробности мы обсудим позже.

Класс DataInputStream

Составляя программы на языке программирования С, вы были вынуждены работать с потоками на уровне байт или, в лучшем случае, на уровне текстовых строк. Однако часто возникает необходимость записывать в потоки данных и читать оттуда объекты других типов, например, целые числа и числа типа double, числа в формате с плавающей десятичной точкой, массивы байт и символов и так далее.

Класс DataInputStream содержит методы, позволяющие извлекать из входного потока данные в перечисленных выше форматах или, как говорят, выполнять форматированный ввод данных. Он также реализует интерфейс DataInput, служащий для этой же цели. Поэтому класс DataInputStream очень удобен и часто применяется в приложениях для работы с потоками ввода.

Так же как и конструктор класса BufferedInputStream, конструктор класса DataInputStream должен получить через свои параметр ссылку на объект класса InputStream.

Класс LineNumberInputStream

С помощью класса LineNumberInputStream вы можете работать с текстовыми потоками, состоящими из отдельных строк, разделенных символами возврата каретки \r и перехода на следующую строку \n. Методы этого класса позволяют следить за нумерацией строк в таких потоках.

Класс PushBackInputStream

Класс PushBackInputStream позволяет возвратить в поток ввода только что прочитанный оттуда символ, с тем чтобы после этого данный символ можно было прочитать снова.

Класс ByteArrayInputStream

При необходимости вы можете создать в приложениях Java входной поток данных не на базе локального или удаленного файла, а на базе массива, расположенного в оперативной памяти. Класс ByteArrayInputStream предназначен именно для этого - вы передаете конструктору класса ссылку на массив, и получаете входной поток данных, связанный с этим массивом.

Потоки в оперативной памяти могут быть использованы для временного хранения данных. Заметим, что так как аплеты Java не могут обращаться к локальным файлам, для создания временных файлов можно использовать потоки в оперативной памяти на базе класса ByteArrayInputStream. Другую возможность предоставляет класс StringBufferInputStream, рассмотренный ниже.

Класс StringBufferInputStream

Класс StringBufferInputStream позволяет создавать потоки ввода на базе строк класса String, используя при этом только младшие байты хранящихся в такой строке символов. Этот класс может служить дополнением для класса ByteArrayInputStream, который также предназначен для создания потоков на базе данных из оперативной памяти.

Класс FileInputStream

Этот класс позволяет создать поток ввода на базе класса File или FileDescriptor.

Класс PipedInputStream

С помощью классов PipedInputStream и PipedOutputStream можно организовать двухстороннюю передачу данных между двумя одновременно работающими задачами мультизадачного аплета.

Класс SequenceInputStream

Класс SequenceInputStream позволяет объединить несколько входных потоков в один поток. Если в процессе чтения будет достигнут конец первого потока такого объединения, в дальнейшем чтение будет выполняться из второго потока и так далее.

Производные от класса OutputStream

Класс OutputStream предназначен для создания потоков вывода. Приложения, как правило, непосредственно не используют этот класс для операций вывода, так же как и класс InputStream для операций ввода. Вместо этого применяются классы, иерархия которых показана на рис. 3.

pic03.gif (3919 bytes)

Рис. 3. Классы, производные от класса OutputtStream

Рассмотрим кратко назначение этих классов.

Класс FilterOutputStream

Абстрактный класс FilterOutputStream служит прослойкой между классом OutputStream и классами BufferedOutputStream, DataOutputStream, а также PrintStream. Он выполняет роль, аналогичную роли рассмотренного ранее класса FilterIntputStream.

Класс BufferedOutputStream

Класс BufferedOutputStream предназначен для создания буферизованных потоков вывода. Как мы уже говорили, буферизация ускоряет работу приложений с потоками.

Класс DataOutputStream

С помощью класса DataOutputStream приложения Java могут выполнять форматированный вывод данных. Для ввода форматированных данных вы должны создать входной поток с использованием класса DataInputStream, о котором мы уже говорили. Класс DataOutputStream реализует интерфейс DataOutput.

Класс PrintStream

Потоки, созданные с использованием класса PrintStream, предназначены для форматного вывода данных различных типов с целью их визуального представления в виде текстовой строки. Аналогичная операция в языке программирования С выполнялась функцией printf.

Класс ByteArrayOutputStream

С помощью класса ByteArrayOutputStream можно создать поток вывода в оперативной памяти.

Класс FileOutputStream

Этот класс позволяет создать поток вывода на базе класса File или FileDescriptor.

Класс PipedOutputStream

Как мы уже говорили, классы PipedInputStream и PipedOutputStream предназначены для организации двухсторонней передачи данных между двумя одновременно работающими задачами мультизадачного аплета.


Классы потоков
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Работа со стандартными потоками

Назад Вперед

Приложению Java доступны три стандратных потока, которые всегда открыты: стандартный поток ввода, стандартный поток вывода и стандартный поток вывода сообщений об ошибках.

Все перечисленные выше потоки определены в классе System как статические поля с именами, соответственно, in, out и err:

public static PrintStream err;
public static InputStream in;
public static PrintStream out;

Заметим, что стандратные потоки, как правило, не используются аплетами, так как браузеры общаются с пользователем через окно аплета и извещения от мыши и клавиатуры, а не через консоль.

Стандартный поток ввода

Стандартный поток ввода in определен как статический объект класса InputStream, который содержит только простейшие методы для ввода данных. Нужнее всего вам будет метод read:

public int read(byte b[]);

Этот метод читает данные из потока в массив, ссылка на который передается через единственный параметр. Количество считанных данных определяется размером массива, то есть значением b.length.

Метод read возвращает количество прочитанных байт данных или -1, если достигнут конец потока. При возникновении ошибок создается исключение IOException, обработку которого необходимо предусмотреть.

Стандартный поток вывода

Стандартный поток вывода out создан на базе класса PrintStream, предназначенного, как мы это отмечали раньше, для форматированного вывода данных различного типа с целью их визуального отображения в виде текстовой строки.

Для работы со стандартным потоком вывода вы будете использовать главным образом методы print и println, хотя метод write также доступен.

В классе PrintStream определено несколько реализаций метода print с параметрами различных типов:

public void print(boolean b);
public void print(char c);
public void print(char s[]);
public void print(double d);
public void print(float f);
public void print(int i);
public void print(long l);
public void print(Object obj);
public void print(String s);

Как видите, вы можете записать в стандартный поток вывода текстовое представление данных различного типа, в том числе и класса Object.

Метод println аналогичен методу print, отличаясь лишь тем, что он добавляет к записываемой в поток строке символ перехода на следующую строку:

public void println();
public void println(boolean b);
public void println(char c);
public void println(char s[]);
public void println(double d);
public void println(float f);
public void println(int i);
public void println(long l);
public void println(Object obj);
public void println(String s);

Реализация метода println без параметров записывает только символ перехода на следующую строку.

Стандртный поток вывода сообщений об ошибках

Стандртный поток вывода сообщений об ошибках err так же, как и стадартный поток вывода out, создан на базе класса PrintStream. Поэтому для записи сообщений об ошибках вы можете использовать только что описанные методы print и println.


Классы потоков
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Создание потоков, связанных с файлами

Назад Вперед

Если вам нужно создать входной или выходной поток, связанный с локальным файлом, следует воспользоваться классами из библиотеки Java, созданными на базе классов InputStream и OutputStream. Мы уже кратко рассказывали об этих классах в разделе "Классы Java для работы с потоками". Однако методика использования перечисленных в этом разделе классов может показаться довольно странной.

В чем эта странность?

Говоря кратко, странность заключается в том, что для создания потока вам необходимо воспользоваться сразу несколькими классами, а не одним, наиболее подходящим для решения поставленной задачи, как это можно было бы предположить.

Поясним сказанное на примере.

Пусть, например, нам нужен выходной поток для записи форматированных данных (скажем, текстовых строк класса String). Казалось бы, достаточно создать объект класса DataOutputStream, - и дело сделано. Однако не все так просто.

В классе DataOutputStream предусмотрен только один конструктор, которому в качестве параметра необходимо передать ссылку на объект класса OutputStream:

public DataOutputStream(OutputStream out);

Что же касается конструктора класса OutputStream, то он выглядит следующим образом:

public OutputStream();

Так как ни в том, ни в другом конструкторе не предусмотрено никаких ссылок на файлы, то непонятно, как с использованием только одних классов OutputStream и DataOutputStream можно создать выходной поток, связанный с файлом.

Что же делать?

Создание потока для форматированного обмена данными

Оказывается, создание потоков, связанных с файлами и предназначенных для форматированного ввода или вывода, необходимо выполнять в несколько приемов. При этом вначале необходимо создать потоки на базе класса FileOutputStream или FileInputStream, а затем передать ссылку на созданный поток констркутору класса DataOutputStream или DataInputStream.

В классах FileOutputStream и FileInputStream предусмотрены конструкторы, которым в качестве параметра передается либо ссылка на объект класса File, либо ссылка на объект класса FileDescriptor, либо, наконец, текстовая строка пути к файлу:

public FileOutputStream(File file);
public FileOutputStream(
  FileDescriptor fdObj);
public FileOutputStream(String name);

Таким образом, если вам нужен выходной поток для записи форматированных данных, вначале вы создаете поток как объект класса FileOutputStream. Затем ссылку на этот объект следует передать конструктору класса DataOutputStream. Полученный таким образом объект класса DataOutputStream можно использовать как выходной поток, записывая в него форматированные данные.

Добавление буферизации

А что, если нам нужен не простой выходной поток, а буферизованный?

Здесь нам может помочь класс BufferedOutputStream. Вот два конструктора, предусмотренных в этом классе:

public BufferedOutputStream(
  OutputStream out);
public BufferedOutputStream(
  OutputStream out, int size);

Первый из них создает буферизованный выходной поток на базе потока класса OutputStream, а второй делает то же самое, но дополнительно позволяет указать размер буфера в байтах.

Если вам нужно создать выходной буферизованный поток для записи форматированных данных, создание потока выполняется в три приема:

  • создается поток, связанный с файлом, как объект класса FileOutputStream;
  • ссылка на этот поток передается конструктору класса BufferedOutputStream, в результате чего создается буферизованный поток, связанный с файлом;
  • ссылка на буферизованный поток, созданный на предыдущем шаге, передается конструктору класса DataOutputStream, который и создает нужный поток

Вот фрагмент исходного текста программы, который создает выходной буферизованный поток для записи форматированных данных в файл с именем output.txt:

DataOutputStream OutStream;
OutStream = new DataOutputStream(
  new BufferedOutputStream(
  new FileOutputStream("output.txt")));

Аналогичным образом создается входной буферизованный поток для чтения форматированных данных из того же файла:

DataInputStream InStream;
InStream = new DataInputStream(
  new BufferedInputStream(
  new FileInputStream("output.txt")));

Исключения при создании потоков

При создании потоков на базе классов FileOutputStream и FileInputStream могут возникать исключения FileNotFoundException, SecurityException, IOException.

Исключение FileNotFoundException возникает при попытке открыть входной поток данных для несуществующего файла, то есть когда файл не найден.

Исключение SecurityException возникает при попытке открыть файл, для которого запрещен доступ. Например, если файл можно только читать, а он открывается для записи, возникнет исключение SecurityException.

Если файл не может быть открыт для записи по каким-либо другим причинам, возникает исключение IOException.


Запись и чтение потоков
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Запись данных в поток и чтение данных из потока

Назад Вперед

Для обмена данными с потоками можно использовать как простейшие методы write и read, так и методы, допускающие ввод или вывод форматированных данных. В зависимости от того, на базе какого класса создан поток, зависит набор доступных методов, предназначенных для чтения или записи данных.

Простейшие методы

Создав выходной поток на базе класса FileOutputStream, вы можете использовать для записи в него данных три разновидности метода write, прототипы которых представлены ниже:

public void write(byte b[]);
public void write(byte b[],
  int off, int len);
public void write(int b);

Первый из этих методов записывает в поток содержимое массива, ссылка на который передается через параметр, начиная с текущей позиции в потоке. После выполнения записи текущая позиция продвигается вперед на число записанных байт, которое при успешном завершении операции равно длине массива (b.length).

Второй метод позволяет дополнительно указать начальное смещение off записываемого блока данных в массиве и количество записываемых байт len.

Третий метод просто записывает в поток один байт данных.

Если в процессе записи происходит ошибка, возникает исключение IOException.

Для входного потока, созданного на базе класса FileInputStream, определены три разновидности метода read, выполняющего чтение данных:

public int read();
public int read(byte b[]);
public int read(byte b[],
  int off, int len);

Первая разновидность просто читает из потока один байт данных. Если достигнут конец файла, возвращается значение -1.

Вторая разновидность метода read читает данные в массив, причем количество прочитанных данных определяется размером массива. Метод возвращает количество прочитанных байт данных или значение -1, если в процессе чтения был достигнут конец файла.

И, наконец, третий метод позволяет прочитать данные в область массива, заданную своим смещением и длиной.

Если при чтении происходит ошибка, возникает исключение IOException.

Методы для чтения и записи форматированных данных

Вместо того чтобы записывать в потоки и читать оттуда отдельные байты или массивы байт, программисты обычно предпочитают пользоваться намного более удобными методами классов DataOutputStream и DataInputStream, допускающими форматированный ввод и вывод данных.

Вот, например, какой набор методов можно использовать для записи форматированных данных в поток класса DataOutputStream:

public final void writeBoolean(boolean v);
public final void writeByte(int v);
public final void writeBytes(String s);
public final void writeChar(int v);
public final void writeChars(String s);
public final void writeDouble(double v);
public final void writeFloat(float v);
public final void writeInt(int v);
public final void writeLong(long v);
public final void writeShort(int v);
public final void writeUTF(String s);

Хотя имена методов говорят сами за себя, сделаем замечания относительно применения некоторых из них.

Метод writeByte записывает в поток один байт. Это младший байт слова, которое передается методу через параметр v. В отличие от метода writeByte, метод writeChar записывает в поток двухбайтовое символьное значение (напомним, что в Java символы хранятся с использованием кодировки Unicode и занимают два байта).

Если вам нужно записать в выходной поток текстовую строку, то это можно сделать с помощью методов writeBytes, writeChars или writeUTF. Первый из этих методов записывает в выходной поток только младшие байты символов, а второй - двухбайтовые символы в кодировке Unicode. Метод writeUTF предназначен для записи строки в машинно-независимой кодировке UTF-8.

Все перечисленные выше методы в случае возникновения ошибки создают исключение IOException, которое вы должны обработать.

В классе DataInputStream определены следующие методы, предназначенные для чтения форматированных данных из входного потока:

public final boolean readBoolean();
public final byte    readByte();
public final char    readChar();
public final double  readDouble();
public final float   readFloat();
public final void    readFully(byte b[]);
public final void    readFully(byte b[],
   int off, int len);
public final int     readInt();
public final String  readLine();
public final long    readLong();
public final short   readShort();
public final int     readUnsignedByte();
public final int     readUnsignedShort();
public final String  readUTF();
public final static String readUTF(
  DataInput in);
public final int     skipBytes(int n);

Обратите внимание, что среди этих методов нет тех, что специально предназначены для четния данных, записанных из строк методами writeBytes и writeChars класса DataOutputStream.

Тем не менее, если входной поток состоит из отдельных строк, разделенных символами возврата каретки и перевода строки, то такие строки можно получить методом readLine. Вы также можете воспользоваться методом readFully, который заполняет прочитанными данными массив байт. Этот массив потом будет нетрудно преобразовать в строку типа String, так как в классе String предусмотрен соответствующий конструктор.

Для чтения строк, записанных методом writeUTF вы должны обязательно пользоваться методом readUTF.

Метод skipBytes позволяет пропустить из входного потока заданное количество байт.

Методы класса DataInputStream, предназначенные для чтения данных, могут создавать исключения IOException и EOFException. Первое из них возникает в случае ошибки, а второе - при достижении конца входного потока в процессе чтения.


Закрывание потоков
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Закрывание потоков

Назад Вперед

Работая с файлами в среде MS-DOS или Windows средствами языка программирования С вы должны были закрывать ненужные более файлы. Так как в системе интерпертации приложений Java есть процесс сборки мусора, возникает вопрос - выполняет ли он автоматическое закрывание потоков, с которыми приложение завершило работу?

Оказывается, процесс сборки мусора не делает ничего подобного!

Сборка мусора выполняется только для объектов, размещенных в оперативной памяти. Потоки вы должны закрывать явным образом, вызывая для этого метод close.


Сброс буферов
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Принудительный сброс буферов

Назад Вперед

Еще один важный момент связан с буферизованными потоками. Как мы уже говорили, буферизация ускоряет работу приложений с потоками, так как при ее использовании сокращается количество обращений к системе ввода/вывода. Вы можете постепенно в течении дня добавлять в поток данные по одному байту, и только к вечеру эти данные будут физически записаны в файл на диске.

Во многих случаях, однако, приложение должно, не отказываясь совсем от буферизации, выполнять принудительную запись буферов в файл. Это можно сделать с помощью метода flush.


Потоки в памяти
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Потоки в оперативной памяти

Назад Вперед

Операционные системы Windows 95 и Windows NT предоставляют возможность для программиста работать с оперативной памятью как с файлом. Это очень удобно во многих случаях. В частности, файлы, отображаемые на память, можно использовать для передачи данных между одновременно работающими задачами и процессами.

При создании приложений и аплетов Java вы также можете работать с объектами оперативной памяти, как с файлами, а точнее говоря, как с потоками. Так как аплетам запрещено обращаться к файлам, расположенным на локальном диске компьютера, при небходимости создания временных потоков ввода или вывода последние могут быть размещены в оперативной памяти.

Ранее мы отмечали, что в библиотеке классов Java есть три класса, специально предназначенных для создания потоков в оперативной памяти. Это классы ByteArrayOutputStream, ByteArrayInputStream и StringBufferInputStream.

Класс ByteArrayOutputStream

Класс ByteArrayOutputStream создан на базе класса OutputStream. В нем имеется два конструктора, прототипы которых представлены ниже:

public ByteArrayOutputStream();
public ByteArrayOutputStream(
  int size);

Первый из этих конструкторов создает выходной поток в оперативной памяти с начальным размером буфера, равным 32 байта. Второй позволяет указать необходимый размер буфера.

В классе ByteArrayOutputStream определено несколько достаточно полезных методов. Вот некоторые из них:

public void reset();
public int size();
public byte[] toByteArray();
public void writeTo(OutputStream out);

Метод reset сбрасывает счетчик байт, записанных в выходной поток. Если данные, записанные в поток вам больше не нужны, вы можете вызвать этот метод и использовать память, выделенную для потока, для записи других данных.

С помощью метода size можно определить количество байт данных, записанных в поток.

Метод toByteArray позволяет скопировать данные, записанные в поток, в массив байт. Этот метод возвращает адрес созданного для этой цели массива.

С помощью метода writeTo вы можете скопировать содержимое данного потока в другой выходной поток, ссылка на который передается методу через параметр.

Для выполнения форматированного вывода в поток, вы должны создать поток на базе класса DataOutputStream, передав соответствующему конструктору ссылку на поток класса ByteArrayOutputStream.

Класс ByteArrayInputStream

С помощью класса ByteArrayInputStream вы можете создать входной поток на базе массива байт, расположенного в оперативной памяти. В этом классе определено два конструктора:

public ByteArrayInputStream(byte buf[]);
public ByteArrayInputStream(
  byte buf[], int offset, int length);

Первый конструктор получает через единственный параметр ссылку на массив, который будет использован для создания входного потока. Второй позволяет дополнительно указать смещение offset и размер области памяти length, которая будет использована для создания потока.

Вот несколько методов, определенных в классе ByteArrayInputStream:

public int available();
public int read();
public int read(byte b[],int off, int len);
public void reset();
public long skip(long n);

Наиболее интересен из них метод available, с помощью которого можно определить, сколько байт имеется во входном потоке для чтения.

Обычно класс ByteArrayInputStream используется вместе с классом DataInputStream, что позволяет организовать форматный ввод данных.

Класс StringBufferInputStream

Класс StringBufferInputStream предназначен для создания входного потока на базе текстовой строки класса String. Ссылка на эту строку передается конструктору класса StringBufferInputStream через параметр:

public StringBufferInputStream(String s);

В классе StringBufferInputStream определены те же методы, что и в только что рассмотренном классе ByteArrayInputStream. Для более удобной работы вы, вероятно, создадите на базе потока класса StringBufferInputStream поток класса DataInputStream.


Класс Stream Tokenizer
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Класс StreamTokenizer для разбора входных потоков

Назад Вперед

Если вы создаете приложение, предназначенное для обработки текстов (например, транслятор или просто разборщик файла конфигурации, содержащего значения различных параметров), вам может пригодиться класс StreamTokenizer. Создав объект этого класса для входного потока, вы можете легко решить задачу выделения из этого потока отдельных слов, символов, чисел и строк комментариев.

Конструктор класса StreamTokenizer

Для создание объектов класса StreamTokenizer предусмотрен всего один конструктор:

public StreamTokenizer(InputStream istream);

В качестве параметра этому конструктору необходимо передать ссылку на заранее созданный входной поток.

Методы класса StreamTokenizer

Для настройки параметров разборщика StreamTokenizer и получения отдельных элементов входного потока вы должны пользоваться методами, определенными в классе StreamTokenizer. Рассмотрим самые важние из них.

Методы для настройки параметров разборщика

Ниже мы привели прототипы методов, предназначенных для настройки параметров разборщика:

public void commentChar(int ch);
public void slashSlashComments(boolean flag);
public void slashStarComments(boolean flag);
public void quoteChar(int ch);

public void eolIsSignificant(boolean flag);
public void lowerCaseMode(boolean fl);

public void ordinaryChar(int ch);
public void ordinaryChars(int low,int hi);
public void resetSyntax();

public void parseNumbers();
public void whitespaceChars(int low, int hi);
public void wordChars(int low, int hi);

Несколько методов определяют, будет ли разборщик выделять во входном потоке строки комментария и если будет, то какми образом.

С помощью метода commentChar вы можете указать символ комментария. Если в строке входного потока попадется такой символ, то он и все следующие за ним до конца текущей строки символы будут проигнорированы.

Методы SlashSlashComments и slashStarComments позволяют указать, что для входного текста используются разделители комментариев в виде двойного символа '/' и '/* … */', соответственно. Это соответствует способу указания комментариев в программах, составленных на языках программирования С++ и С. Для включения режима выделения комментариев обоим методам в качетстве параметра необходимо передать значение true, а для отключения - false.

Метод quoteChar позволяет задать символ, который будет использован в качестве кавычек. Когда при разборе потока встречаются слова, взятые в кавычки, они возвращаются программе разбора без кавычек.

Если передать методу eolIsSignificant значение true, разделители строк будут интерпретироваться как отдельные элементы. Если же этому методу передать значение false, разделители строк будут использоваться аналогично пробелам для разделения элементов входного потока.

Метод lowerCaseMode позволяет включить режим, при котором все выделенные элементы будут перекодированы в строчные символы.

Методы ordinaryChar и ordinaryChars позволяют указать символы, которые должны интерпретироваться как обычные, из которых составляются слова или цифры. Например, если передать методу ordinaryChar символ '.', то слово java.io будет восприниматься как один элемент. Если же этого не сделать, то разборщик выделит из него три элемента - слово java, точку '.' и слово io. Метод ordinaryChars позволяет указать диапазон значений символов, которые должны интерпретироваться как обычные.

С помощью метода resetSyntax вы можете указать, что все символы будут рассматриваться, как обычные.

Метод parseNumbers включает режим разбора чисел, при котором распознаются и преобразуются числа в формате с плавающей десятичной точкой.

Метод whitespaceChars задает диапазон значений для символов-разделителей отдельных слов в потоке.

Метод wordChars позволяет указать символы, которые являются составными частями слов.

Методы для разбора входного потока

После того как вы создали разборщик входного потока на базе класса StreamTokenizer и установили его параметры с помощью описанных выше методов, можно приступать собственно к разборке потока. Обычно для этого организуется цикл, в котором вызывается метод nextToken:

public int nextToken();

Этот метод может вернуть одно из следующих значений:

Значение | Описание
TT_WORDTT_WORD | Из потока было извлечено слово
TT_NUMBERTT_NUMBER | Из потока было извлечено численное значение
TT_EOLTT_EOL | Обнаружен конец строки. Это значение возвращается только в том случае, если при настройке параметров разборщика был вызван метод eolIsSignficant
TT_EOFTT_EOF | Обнаружен конец файла

Если метод nextToken вернул значение TT_EOF, следует завершить цикл разбора входного потока.

Как извлечь считанные элементы потока?

В классе StreamTokenizer определено три поля:

public String sval;
public double nval;
public int    ttype;

Если метод nextToken вернул значение TT_WORD, в поле sval содержится извлеченный элемент в виде текстовой строки. В том случае, когда из входного потока было извлечено числовое значение, оно будет храниться в поле nval типа double. Обычные символы записываются в поле ttype.

Заметим, что если в потоке обнаружены слова, взятые в кавычки, то символ кавычки записывается в поле ttype, а слова - в поле sval. По умолчанию используется символ кавычек '"', однако с помощью метода quoteChar вы можете задать любой другой символ.

При необходимости в процессе разбора вы можете определить номер текущей строки, вызвав для этого метод lineno:

public int lineno();

После вызова метода pushBack следующий вызов метода nextToken приведет к тому, что в поле ttype будет записано текущее значение, а содержимое полей sval и nval не изменится. Прототип метода pushBack приведен ниже:

public void pushBack();

Метод toString возвращает текстовую строку, представляющую текущий элемент, выделенный из потока:

public String toString();


Класс StringTokenizer
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Класс StringTokenizer

Назад Вперед

Рассказывая о классе StreamTokenizer, нельзя не упомянуть о другом классе с похожим названием и назначением, а именно о классе StringTokenizer.

Определение этого класса достаточно компактно.

  • Конструкторы
public StringTokenizer(String str);
public StringTokenizer(String str,
  String delim);
public StringTokenizer(String str,
  String delim,
  boolean returnTokens);
  • Методы
  public String nextToken();
  public String nextToken(String delim);
  public int countTokenss();
  public boolean hasMoreElements();
  public boolean hasMoreTokenss();
  public Object nextElement();
}

Класс StringTokenizer не имеет никакого отношения к потокам, так как предназначен для выделения отдельных элементов из строк типа String.

Конструкторы класса получают в качетсве первого параметра str ссылку на разбираемую строку. Второй параметр delim, если он есть, задает разделители, с испльзованием которых в строке будут выделяться элементы. Параметр returnTokens определяет, надо ли вовзвращать обнаруженные разделители как элементы разбираемой строки.

Рассмотрим кратко методы класса StringTokenizer.

Для разбора строки приложение должно организовать цикл, вызывая в нем метод nextToken. Условием завершения цикла может быть либо возникновение исключения NoSuchElementException, либо возврат значения false методами hasMoreElements или hasMoreTokens.

Метод countTokens позволяет определить, сколько раз был вызван метод nextToken перед возникновением исключения NoSuchElementException.


Класс File
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Работа с файлами и каталогами при помощи класса File

Назад Вперед

В предыдущих разделах мы рассмотрели классы, предназначенные для чтения и записи потоков. Однако часто возникает необходимость выполнения и таких операций, как определение атрибутов файла, создание или удаление каталогов, удаление файлов, получение списка всех файлов в каталоге и так далее. Для выполнения всех этих операций в приложениях Java используется класс с именем File.

Создание объекта класса File

У вас есть три возможности создать объект класса File, вызвав для этого один из трех конструкторов:

public File(String path);
public File(File dir, String name);
public File(String path, String name);

Первый из этих конструкторов имеет единственный параметр - ссылку на строку пути к файлу или каталогу. С помощью второго конструктора вы можете указать отдельно каталог dir и имя файла, для которого создается объект в текущем каталоге. И, наконец, третий конструктор позволяет указать полный путь к каталогу и имя файла.

Если первому из перечисленных конструкторов передать ссылку со значением null, возникнет исключение NullPointerException.

Пользоваться конструкторам очень просто. Вот, например, как создать объект класса File для файла c:\autoexec.bat и каталога d:\winnt:

f1 = new File("c:\\autoexec.bat");
f2 = new File("d:\\winnt");

Определение атрибутов файлов и каталогов

После того как вы создали объект класса File, нетрудно определить атрибуты этого объекта, воспользовавшись соответствующими методами класса File.

Проверка существования файла или каталога

С помощью метода exists вы можете проверить существование файла или катлога, для которого был создан объект класса File:

public boolean exists();

Этот метод можно применять перед созданием потока на базе класса FileOutputStream, если вам нужно избежать случайной перезаписи существующего файла. В этом случае перед созданием выходного потока класса FileOutputStream следует создать объект класса File, указав конструктору путь к файлу, а затем проверить сущестование файла методом exists.

Проверка возможности чтения и записи

Методы canRead и canWrite позволяют проверить возможность чтения из файла и записи в файл, соответственно:

public boolean canRead();
public boolean canWrite();

Их полезно применять перед созданием соответствующих потоков, если нужно избежать возникновение исключений, связанных с попыткой выполнения доступа неразрешенного типа. Если доступ разрешен, эти методы возвращают значение true, а если запрещен - false.

Определение типа объекта - файл или каталог

С помощью методов isDirectory и isFile вы можете проверить, чему соответствует созданный объект класса File - каталогу или файлу:

public boolean isDirectory();
public boolean isFile();

Получение имени файла или каталога

Метод getName возвращает имя файла или каталога для заданного объекта класса File (имя выделяется из пути):

public String getName();

Получение абсолютного пути к каталогу

Метод getAbsolutePath возвращает абсолютный путь к файлу или каталогу, который может быть машинно-зависимым:

public String getAbsolutePath();

Определение типа указанного пути - абсолютный или относительный

С помощью метода isAbsolute вы можете определить, соответствует ли данный объект класса File файлу или каталогу, заданному абсолютным (полным) путем, либо относительным путем:

public boolean isAbsolute();

Определение пути к файлу или каталогу

Метод getPath позволяет определить машинно-независимый путь файла или каталога:

public String getPath();

Определение родительского каталога

Если вам нужно определить родительский каталог для объекта класса File, то это можно сделать методом getParent:

public String getParent();

Определение длины файла в байтах

Длину файла в байтах можно определить с помощью метода length:

public long length();

Определение времени последней модификации файла или каталога

Для определения времени последней модификации файла или каталога вы можете вызвать метод lastModified:

public long lastModified();

Заметим, однако, что этот метод возвращает время в относительных единицах с момента запуска системы, поэтому его удобно использовать только для относительных сравнений.

Получение текстового представления объекта

Метод toString возвращает текстовую строку, представляющую объект класса File:

public String toString();

Получение значения хэш-кода

Метод hashCode возвращает значение хэш-кода, соответствующего объекту File:

public int hashCode();

Удаление файлов и каталогов

Для удаления ненужного файла или каталога вы должны создать соответствующий объект File и затем вызвать метод delete:

public boolean delete();

Создание каталогов

С помощью методов mkdir и mkdirs можно создавать новые каталоги:

public boolean mkdir();
public boolean mkdirs();

Первый из этих методов создает один каталог, второй - все подкаталоги, ведущие к создаваемому каталогу (то есть полный путь).

Переименование файлов и каталогов

Для переименования файла или каталога вы должны создать два объекта класса File, один из которых соответствует старому имени, а второй - новому. Затем для перовго из этих объектов нужно вызвать метод renameTo, указав ему в качестве параметра ссылку на второй объект:

public boolean renameTo(File dest);

В случае успеха метод возвращает значение true, при возникновении ошибки - false. Может также возникать исключение SecurityException.

Сравнение объектов класса File

Для сравнения объектов класса File вы должны использовать метод equals:

public boolean equals(Object obj);

Заметим, что этот метод сравнивает пути к файлам и каталогам, но не сами файли или каталоги.

Получение списка содержимого каталога

С помощью метода list вы можете получить список содержимого каталога, соответствующего данному объекту класса File. В классе File предусмотрено два варианта этого метода - без параметра и с параметром:

public String[] list();
public String[] list(FilenameFilter filter);

Первый из этих методв возвращает массив строк с именами содержимого каталога, не включая текущий каталог и родительский каталог. Второй позволяет получить список не всех объектов, хранящихся в каталоге, а только тех, что удовлетворяют условиям, определенным в фильтре filter класса FilenameFilter.


Произвольный доступ
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Произвольный доступ к файлам

Назад Вперед

В ряде случаев, например, при создании системы управления базой данных, требуется обеспечить произвольный доступ к файлу. Рассмотренные нами ранее потоки ввода и вывода пригодны лишь для последовательного доступа, так как в соответствующих классах нет средств позиционирования внутри файла.

Между тем библиотека классов Java содержит класс RandomAccessFile, который предназначен специально для организации прямого доступа к файлам как для чтения, так и для записи.

В классе RandomAccessFile определено два конструктора, прототипы которых показаны ниже:

public RandomAccessFile(
  String name, String mode);
public RandomAccessFile(
  File file, String mode);

Первый из них позволяет указывать имя файла, и режим mode, в котором открывается файл. Второй конструктор вместо имени предполагает использование объекта класса File.

Если файл открывается только для чтения, вы должны передать конструктору текстовую строку режима "r". Если же файл открывается и для чтения, и для записи, конструктору передается строка "rw".

Позиционирование внутри файла обеспечивается методом seek, в качестве параметра pos которому передается абсолютное смещение файла:

public void seek(long pos);

После вызова этого метода текущая позиция в файле устанавливается в соответствии со значением параметра pos.

В любой момент времени вы можете определить текущую позицию внутри файла, вызвав метод getFilePointer:

public long getFilePointer();

Еще один метод, который имеет отношение к позиционированию, называется skipBytes:

public int skipBytes(int n);

Он работает так же, как и одноименный метод для потоков - продвигает текущую позицию в файле на заданное количество байт.

С помощью метода close вы должны закрывать файл, после того как работа с им завершена:

public void close();

Метод getFD позволяет получить дескриптор файла:

public final FileDescriptor getFD();

С помощью метода length вы можете определить текущую длину файла:

public long length();

Ряд методов предназначен для выполнения как обычного, так и форматированного ввода из файла. Этот набор аналогичен методам, определенным для потоков:

public int read();
public int read(byte b[]);
public int read(byte b[],int off,int len);
public final boolean readBoolean();
public final byte    readByte();
public final char    readChar();
public final double  readDouble();
public final float   readFloat();
public final void    readFully(byte b[]);
public final void    readFully(byte b[],
   int off, int len);
public final int     readInt();
public final String  readLine();
public final long    readLong();
public final short   readShort();
public final int     readUnsignedBytee();
public final int     readUnsignedShort();
public final String  readUTF();

Существуют также методы, позволяющие выполнять обычную или форматированную запись в файл с прямым доступом:

public void write(byte b[]);
public void write(byte b[],int off,int len);
public void write(int b);
public final void writeBoolean(boolean v);
public final void writeBytee(int v);
public final void writeBytes(String s);
public final void writeChar(int v);
public final void writeChars(String s);
public final void writeDouble(double v);
public final void writeFloat(float v);
public final void writeInt(int v);
public final void writeLong(long v);
public final void writeShort(int v);
public final void writeUTF(String str);

Имена приведенных методов говорят сами за себя, поэтому мы не будем их описывать.


Приложение StreamToken
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Приложение StreamToken

Назад Вперед

В приложении StreamToken мы демонстрируем использование класса StreamTokenizer для разбора входного потока.

Вначале приложение запрашивает у пользователя строку для разбора, записывая ее в файл. Затем этот файл открывается для чтения буферизованным потоком и разбирается на составные элементы. Каждый такой элемент выводится в отдельной строке, как это показано на рис. 4.

pic04.gif (5983 bytes)

Рис. 4. Разбор входного потока в приложении StreamToken

Обратите внимание, что в процессе разбора значение 3.14 было воспринято как числовое, а 3,14 - нет. Это потому, что при настройке разборщика мы указали, что символ '.' является обычным.

Исходный текст приложения

Исходный текст приложения StreamToken представлен в листинге 1.

Листинг 1. Файл StreamToken.java

import java.io.*;
public class StreamToken
{
  public static void main(String args[])
  {
    DataOutputStream OutStream;
    DataInputStream  InStream;
    byte bKbdInput[] = new byte[256];
    String sOut;
    try
    {
      System.out.println(
        "Enter string to parse...");
      System.in.read(bKbdInput);
      sOut = new String(bKbdInput, 0);
      OutStream = new DataOutputStream(
        new BufferedOutputStream(
          new FileOutputStream(
           "output.txt")));
      OutStream.writeBytes(sOut);
      OutStream.close();
      InStream = new DataInputStream(
        new BufferedInputStream(
          new FileInputStream(
            "output.txt")));
      TokenizerOfStream tos =
        new TokenizerOfStream();
      tos.TokenizeIt(InStream);
      InStream.close();
      System.out.println(
        "Press <Enter> to terminate...");
      System.in.read(bKbdInput);
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
}
class TokenizerOfStream
{
  public void TokenizeIt(InputStream is)
  {
    StreamTokenizer stok;
    String str;
    try
    {
      stok = new StreamTokenizer(is);
      stok.slashSlashComments(true);
      stok.ordinaryChar('.');
      while(stok.nextToken() !=
         StreamTokenizer.TT_EOF)
      {
        switch(stok.ttype)
        {
          case StreamTokenizer.TT_WORD:
          {
            str = new String(
              "\nTT_WORD >" + stok.sval);
            break;
          }
          case StreamTokenizer.TT_NUMBER:
          {
            str = "\nTT_NUMBER >" +
               Double.toString(stok.nval);
            break;
          }
          case StreamTokenizer.TT_EOL:
          {
            str = new String("> End of line");
            break;
          }
          default:
            {
              if((char)stok.ttype == '"')
              {
                str = new String(
                  "\nTT_WORD >" + stok.sval);
              }
              else
                str = "> " +
                  String.valueOf(
                    (char)stok.ttype);
            }
        }
        System.out.println(str);
      }
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
}

Описание исходного текста приложения

После ввода строки с клавиатуры и записи ее в файл через поток наше приложение создает входной буферизованный поток, как это показано ниже:

InStream = new DataInputStream(
  new BufferedInputStream(
  new FileInputStream("output.txt")));

Далее для этого потока создается разборщик, который оформлен в отдельном классе TokenizerOfStream, определенном в нашем приложении:

TokenizerOfStream tos =
  new TokenizerOfStream();

Вслед за этим мы вызываем метод TokenizeIt, определенный в классе TokenizerOfStream, передавая ему в качестве параметра ссылку на входной поток:

tos.TokenizeIt(InStream);

Метод TokenizeIt выполняет разбор входного потока, отображая результаты разбора на консоли. После выполнения разбора входной поток закрывается методом close:

InStream.close();

Самое интересное в нашем приложении связано, очевидно, с классом TokenizerOfStream, поэтому перейдем к его описанию.

В этом классе определен только один метод TokenizeIt:

public void TokenizeIt(InputStream is)
{
  . . .
}

Получая в качестве параметра ссылку на входной поток, он прежде всего создает для него разборщик класса StreamTokenizer:

StreamTokenizer stok;
stok = new StreamTokenizer(is);

Настройка параметров разборщика очень проста и сводится к вызовам всего двух методов:

stok.slashSlashComments(true);
stok.ordinaryChar('.');

Метод slashSlashComments включает режим распознавания комментариев в стиле языка программирования С++, а метод ordinaryChar объявляет символ '.' обычным символом.

После настройки запускается цикл разбора входного потока, причем условием завершения цикла является достижение конца этого потока:

while(stok.nextToken() !=
  StreamTokenizer.TT_EOF)
{
  . . .
}

В цикле анализируется содержимое поля ttype, которое зависит от типа элемента, обнаруженного во входном потоке:

switch(stok.ttype)
{
  case StreamTokenizer.TT_WORD:
  {
    str = new String("\nTT_WORD >"
       + stok.sval);
    break;
  }
  case StreamTokenizer.TT_NUMBER:
  {
    str = "\nTT_NUMBER >" +
      Double.toString(stok.nval);
    break;
  }
  case StreamTokenizer.TT_EOL:
  {
    str = new String("> End of line");
    break;
  }
  default:
  {
    if((char)stok.ttype == '"')
      str = new String(
        "\nTT_WORD >" + stok.sval);
    else
      str = "> " + String.valueOf(
       (char)stok.ttype);
  }
}

На слова и численные значения мы реагируем очень просто - записываем их текстовое представление в рабочую переменную str типа String. При обнаружении конца строки в эту переменную записывается строка End of line.

Если же обнаружен обычный символ, мы сравниваем его с символом кавычки. При совпадении в переменную str записывается содержимое поля sval, в котором находятся слова, обнаруженные внутри кавычек. Если же обнаруженный символ не является символом кавычки, он преобразуется в строку и записывается в переменную str.

В заключении метод выводит строку str в стандартный поток вывода, отображая на консоли выделенный элемент потока:

System.out.println(str);


Приложение DirectFile
Работа с файлами
Классы потоков
Стандартные потоки
Потоки и файлы
Запись и чтение потоков
Закрывание потоков
Сброс буферов
Потоки в памяти
Класс Stream Tokenizer
Класс StringTokenizer
Класс File
Произвольный доступ
Приложение StreamToken
Приложение DirectFile

Приложение DirectFile

Назад Вперед

Для иллюстрации способов работы с классом RandomAccessFile мы подготовили приложение DirectFile, в котором создается небольшая база данных. Эта база данных состоит из двух файлов: файла данных и файла индекса.

В файле данных хранятся записи, сосотящие из двух полей - текстового и числового. Текстовое поле с названием name хранит строки, закрытые смиволами конца строки "\r\n", а числовое с названием account - значения типа int.

В меню File нашего приложения есть строки New и View records (рис. 5).

pic05.gif (2516 bytes)

Рис. 5. Строки меню File

С помощью строки New вы можете создать базу данных, состоящую из трех записей. Если выбрать из меню File строку View records, на экране появится диалоговая панель с содержимым этих записей (рис. 6).

pic06.gif (2365 bytes)

Рис. 6. Содержимое трех первых полей базы данных

Вместо символа перевода строки в диалоговой панели отображается маленький квадратик.

Дамп создаваемого файла данных приведен на рис. 7.

pic07.gif (1956 bytes)

Рис. 7. Дамп файла данных

Из этого дампа видно, что после первого запуска приложения в файле данных имеются следующие записи:

Номер записи | Смещение в файле данных | Поле name | Поле account
0 | 0 | Ivanov | 1000
1 | 12 | Petrov | 2000
2 | 24 | Sidoroff | 3000

При последующих запусках каждый раз в файл данных будут добавляться приведенные выше записи.

Так как поле name имеет переменную длину, для обеспечения возможности прямого доступа к записи по ее номеру необходимо где-то хранить смещения всех записей. Мы это делаем в файле индексов, дамп которого представлен на рис. 8.

pic08.gif (1575 bytes)

Рис. 8. Дамп файла индекса

Файл индексов хранит 8-байтовые смещения записей файла данных в формате long. Зная номер записи, можнор легко вычислить смещение в файле индексов, по которому хранится смещение нужной записи в файле данных. Если извлечь это смещение, то можно выполнить позиционирование в файле данных с целью чтения нужной записи, что и делает наше приложение.

Исходный текст приложения DirectFile

Исходный текст приложения DirectFile представлен в листинге 2.

Листинг 2. Файл DirectFile.java

import java.awt.*;
import java.io.*;
import java.util.*;
public class DirectFile
{
  public static void main(String args[])
  {
    MainFrameWnd frame =
      new MainFrameWnd("MenuApp");
    frame.setSize(
    frame.getInsets().left +
      frame.getInsets().right  + 320,
      frame.getInsets().top  +
      frame.getInsets().bottom + 240);
    frame.show();
  }
}
class MainFrameWnd extends Frame
{
  MenuBar mbMainMenuBar;
  Menu mnFile;
  Menu mnHelp;
  boolean fDBEmpty = true;
  public MainFrameWnd(String sTitle)
  {
    super(sTitle);
    setSize(400, 200);
    setBackground(Color.yellow);
    setForeground(Color.black);
    setLayout(new FlowLayout());
    mbMainMenuBar = new MenuBar();
    mnFile = new Menu("File");
    mnFile.add("New...");
    mnFile.add("View records...");
    mnFile.add("-");
    mnFile.add("Exit");
    mnHelp = new Menu("Help");
    mnHelp.add("Content");
    mnHelp.add("-");
    mnHelp.add("About");
    mbMainMenuBar.add(mnFile);
    mbMainMenuBar.add(mnHelp);
    setMenuBar(mbMainMenuBar);
  }
  public void paint(Graphics g)
  {
    g.setFont(new Font("Helvetica",
      Font.PLAIN, 12));
    g.drawString("Frame window", 10, 70);
    super.paint(g);
  }
  public boolean handleEvent(Event evt)
  {
    if(evt.id == Event.WINDOW_DESTROY)
    {
      setVisible(false);
      System.exit(0);
      return true;
    }
    else
      return super.handleEvent(evt);
  }
  public boolean action(Event evt,
   Object obj)
  {
    MenuItem mnItem;
    if(evt.target instanceof MenuItem)
    {
      mnItem = (MenuItem)evt.target;
      if(obj.equals("Exit"))
      {
        System.exit(0);
      }
      else if(obj.equals("New..."))
      {
    if(fDBEmpty)
     {
      SimpleDBMS db = new SimpleDBMS(
        "dbtest.idx", "dbtest.dat");
          db.AddRecord("Ivanov",   1000);
          db.AddRecord("Petrov",   2000);
      db.AddRecord("Sidoroff", 3000);
          db.close();
      fDBEmpty = false;
          MessageBox mbox;
          mbox = new MessageBox(
            "Database created",
            this, "Information", true);
      mbox.show();
    }
      }
      else if(obj.equals("View records..."))
      {
        SimpleDBMS db = new SimpleDBMS(
      "dbtest.idx", "dbtest.dat");
        String szRecords;

    szRecords =
          db.GetRecordByNumber(0) +
      db.GetRecordByNumber(1) +
      db.GetRecordByNumber(2);

        db.close();

        MessageBox mbox;
        mbox = new MessageBox(szRecords,
          this, "Database records", true);
    mbox.show();
      }

      else if(obj.equals("Content"))
      {
        MessageBox mbox;
        mbox = new MessageBox(
          "Item Content selected",
          this, "Dialog from Frame", true);
        mbox.show();
      }

      else if(obj.equals("About"))
      {
        MessageBox mbox;
        mbox = new MessageBox(
          "Item About selected",
          this, "Dialog from Frame", true);
        mbox.show();
      }
      else
        return false;
      return true;
    }
    return false;
  }
}
class MessageBox extends Dialog
{
  Label lbMsg;
  Button btnOK;
  public MessageBox(String sMsg,
    Frame  parent, String  sTitle,
    boolean  modal)
  {
    super(parent, sTitle, modal);
    resize(300, 100);
    setLayout(new GridLayout(2, 1));
    lbMsg = new Label(sMsg, Label.CENTER);
    add(lbMsg);
    btnOK = new Button("OK");
    add(btnOK);
  }
  public boolean handleEvent(Event evt)
  {
    if(evt.id == Event.WINDOW_DESTROY)
    {
      dispose();
      return true;
    }
    else
      return super.handleEvent(evt);
  }
  public boolean action(Event evt,
   Object obj)
  {
    Button btn;
    if(evt.target instanceof Button)
    {
      btn = (Button)evt.target;
      if(evt.target.equals(btnOK))
      {
        dispose();
      }
      else
        return false;
      return true;
    }
    return false;
  }
}
class SimpleDBMS
{
  RandomAccessFile idx;
  RandomAccessFile dat;
  long idxFilePointer = 0;
  public SimpleDBMS(String IndexFile,
   String DataFile)
  {
    try
    {
      idx = new RandomAccessFile(
        IndexFile, "rw");
      dat = new RandomAccessFile(
        DataFile, "rw");
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
  public void close()
  {
    try
    {
      idx.close();
      dat.close();
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
  public void AddRecord(String name,
     int account)
  {
    try
    {
      idx.seek(idx.length());
      dat.seek(dat.length());
      idxFilePointer = dat.getFilePointer();
      idx.writeLong(idxFilePointer);
      dat.writeBytes(name+ "\r\n");
      dat.writeInt(account);
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
  public String GetRecordByNumber(long nRec)
  {
    String sRecord = "<empty>";

    try
    {
      Integer account;
      String str = null;
      idx.seek(nRec * 8);
      idxFilePointer = idx.readLong();
      dat.seek(idxFilePointer);
      str = dat.readLine();
      account = new Integer(dat.readInt());
      sRecord = new String("> " +
       account + ", " + str);
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
    return sRecord;
  }
}

Описание исходного текста приложения DirectFile

Для работы с базой данных мы создали класс SimpleDBMS, определив в нем конструктор, методы для добавления записей, извлечения записей по их порядковому номеру, а также метод для закрытия базы данных.

Создание базы данных

Когда пользователь выбирает из меню File строку New, соответствующий обработчик события создает базу данных, передавая конструктору имена файла индекса dbtest.idx и файла данных dbtest.dat:

SimpleDBMS db = new SimpleDBMS(
  "dbtest.idx", "dbtest.dat");

После этого с помощью метода AddRecord, определенного в классе SimpleDBMS, в базу добавляются три записи, состоящие из текстового и числового полей:

db.AddRecord("Ivanov",   1000);
db.AddRecord("Petrov",   2000);
db.AddRecord("Sidoroff", 3000);

После завершения работы с базой данных она закрывается методом close из класса SimpleDBMS:

db.close();

Просмотр записей базы данных

При выборе строки View records из меню File приложение открывает файл базы данных:

SimpleDBMS db = new SimpleDBMS(
  "dbtest.idx", "dbtest.dat");

Затем оно извлекает три записи с номерами 0, 1 и 2, вызывая для этого метод GetRecordByNumber, также определенный в классе SimpleDBMS:

String szRecords;

szRecords = db.GetRecordByNumber(0) +
  db.GetRecordByNumber(1) +
  db.GetRecordByNumber(2);

Записи объединяются и сохраняются в переменной szRecords типа String. После этого база данных закрывается:

db.close();

Для отображения содержимого записей мы создаем диалоговую панель на базе определенного нами класса MessageBox:

MessageBox mbox;
mbox = new MessageBox(szRecords,
  this, "Database records", true);
mbox.show();

Класс SimpleDBMS

Рассмотрим теперь класс SimpleDBMS.

В этом классе определено три поля с именами idx, dat и idxFilePointer, а также три метода.

Поля класса SimpleDBMS

Поля idx и dat являются объектами класса RandomAccessFile и представляют собой, соответственно, ссылки на файл индекса и файл данных. Поле idxFilePointer типа long используется как рабочее и хранит текущее смещение в файле.

Конструктор класса SimpleDBMS

Конструктор класса SimpleDBMS выглядит достаточно просто. Все, что он делает, - это создает два объекта класса RandomAccessFile, соответственно, для индекса и данных:

idx = new RandomAccessFile(IndexFile, "rw");
dat = new RandomAccessFile(DataFile, "rw");

Так как в качестве второго параметра конструктору класа RandomAccessFile передается строка "rw", файлы открываются и для чтения, и для записи.

Метод close

Метод close закрывает файлы индекса и данных, вызывая метод close из класса RandomAccessFile:

idx.close();
dat.close();

Метод AddRecord

Метод AddRecord добавляет новую запись в конец файла данных, а смещение этой записи - в конец файла индекса. Поэтому перед началом своей работы текущая позиция обоих указанных файлов устанавливается на конец файла.

Для установки мы применили метод seek из класса RandomAccessFile, передав ему в качестве параметра значение длины файла в байтах, определенное при помощи метода length из того же класса:

idx.seek(idx.length());
dat.seek(dat.length());

Перед тем как добавлять новую запись в файл данных, метод AddRecord определяет текущую позицию в файле данных (в данном случае это позиция конца файла) и записывает эту позицию в файл индекса:

idxFilePointer = dat.getFilePointer();
idx.writeLong(idxFilePointer);

Далее метод AddRecord выполняет сохранение полей записи в файле данных. Для записи строки вызывается метод writeBytes, а для записи численного значения типа int - метод writeInt:

dat.writeBytes(name + "\r\n");
dat.writeInt(account);

Обратите внимение, что к строке мы добавляем символы возврата каретки и перевода строки. Это сделано исключительно для того чтобы обозначить конец строки текстового поля.

Метод GetRecordByNumber

Метод GetRecordByNumber позволяет извлечь произвольную запись из файла данных по ее порядковому номеру.

Напомним, что смещения всех записей хранятся в файле индексов и имеют одинаковую длину 8 байт. Пользуясь этим, метод GetRecordByNumber вычисляет смещение в файле индекса простым умножением порядкового номера записи на длину переменной типа long, то есть на 8 байт, а затем выполняет позиционирование:

idx.seek(nRec * 8);

После этого метод GetRecordByNumber извлекает из файла индексов смещение нужной записи в файле данных, вызывая для этого метод readLong, а затем выполняет позиционирование в файле данных:

idxFilePointer = idx.readLong();
dat.seek(idxFilePointer);

Поля записи читаются из файла данных в два приема. Вначале читается строка текстового поля, а затем - численное значение, для чего вызываются, соответственно, методы readLine и readInt:

str = dat.readLine();
account = new Integer(dat.readInt());

Полученные значения полей объединяются в текстовой строке и записываются в переменную sRecord:

sRecord = new String("> " +
  account + ", " + str);

Содержимое этой переменной метод GetRecordByNumber возвращает в качестве извлеченной строки записи базы данных.


Сетевые приложения
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Создание сетевых приложений

Назад Вперед

Когда мы начинали разговор про язык программирования Java, то отмечали, что он специально ориентирован на глобальные сети, такие как Internet. В этой главе мы начнем знакомство с конкретными классами Java, разработанными для сетевого программирования. На примере наших приложений вы сможете убедиться, что классы Java действительно очень удобны для создания сетевых приложений.

В этой главе мы рассмотрим два аспекта сетевого программирования. Первый из них касается доступа из приложений Java к файлам, расположенным на сервере Web, второй - создания серверных и клиентских приложений с использованием сокетов.

Напомним, что из соображений безопасности алпетам полностью запрещен доступ к локальным файлам рабочей станции, подключенной к сети. Тем не менее, аплет может работать с файлами, расположенными на серверах Web. При этом можно использовать входные и выходные потоки, описанные нами в предыдущей главе.

Для чего аплетам обращаться к файлам сервера Web?

Таким аплетам можно найти множество применений.

Представьте себе, например, что вам нужно отображать у пользователя диаграмму, исходные данные для построения которой находятся на сервере Web. Эту задачу можно решить, грубо говоря, двумя способами.

Первый заключается в том, что вы создаете расширение сервера Web в виде приложения CGI или ISAPI, которое на основании исходных данных динамически формирует графическое изображение диаграммы в виде файла GIF и посылает его пользователю.

Однако на пути решения задачи с помощью расширения сервера Web вас поджидают две неприятности. Во-первых, создать из программы красивый цветной графический файл в стандарте GIF не так-то просто - вы должны разобраться с форматом этого файла и создать все необходимые заголовки. Во-вторых, графический файл занимает много места и передается по каналам Internet достаточно медленно - средняя скорость передачи данных в Internet составляет 1 Кбайт в секунду.

В то же время файл с исходными данными может быть очень компактным. Возникает вопрос - нельзя ли передавать через Internet только исходные данные, а построение графической диаграммы выполнять на рабочей станции пользователя?

В этом заключается второй способ, который предполагает применение аплетов. Ваше приложение может, например, получать через сеть файл исходных данных, а затем на основании содержимого этого файла рисовать в своем окне цветную круговую диаграмму. Объем передаваемых данных при этом по сравнению с использованием расширения сервера Web сокращается в десятки и сотни раз.

Помимо работы с файлами, расположенными на сервере Web, мы расскажем о создании каналов между приложениями Java, работающими на различных компьютерах в сети, с использованием сокетов.

Сокеты позволяют организовать тесное взаимодействие аплетов и полноценных приложений Java, при котором аплеты могут предавать друг другу данные через сеть Internet. Это открывает широкие возможности для обработки информации по схеме клиент-сервер, причем в роли серверов здесь может выступать любой компьютер, подключенный к сети, а не только сервер Web. Каждая рабочая станция может выступать одновременно и в роли сервера, и в роли клиента.


Адрес IP
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Адрес IP и класс InetAddress

Назад Вперед

Прежде чем начинать создание сетевых приложений для Internet, вы должны разобраться с адресацией компьютеров в сети с протоколом TCP/IP, на базе которого построена сеть Internet. Здесь мы приведем самые необходимые для этого сведения.

Все компьютеры, подключенные к сети TCP/IP, называются узлами (в оригинальной терминологии узел - это host). Каждый узел имеет в сети свой адрес IP, состоящий из четырех десятичных цифр в диапазоне от 0 до 255, разделенных символом "точка ", например:

193.120.54.200

Фактически адрес IP является 32-разрядным двоичным числом. Упомянутые числа представляют собой отдельные байты адеса IP.

Так как работать с цифрами удобно лишь компьютеру, была придумана система доменных имен. При использовании этой системы адресам IP ставится в соответсвие так называемый доменный адрес, такой как, например, www.sun.com.

В сети Internet имеется распределенная по всему миру база доменных имен, в которой установлено соответствие между доменными именами и адресами IP в виде четырех чисел.

Для работы с адресами IP в библиотеке классов Java имеется класс InetAddress, определение наиболее интересных методов которого приведено ниже:

public static  InetAddress getLocalHost();
public static  InetAddress
  getByName(String host);
public static  InetAddress[]
  getAllByName(String host);
public byte[]  getAddress();
public String  toString();
public String  getHostName();
public boolean equals(Object obj);

Рассмотрим применение этих методов.

Чтобы работать с адресами IP, прежде всего вы должны создать объект класса InetAddress. Эта процедура выполняется не с помощью оператора new, а с применением статических методов getLocalHost, getByName и getAllByName.

Создание объекта класса InetAddress для локального узла

Метод getLocalHost создает объект класса InetAddress для локального узла, то есть для той рабочей станции, на которой выполняется приложение Java. Так как этот метод статический, вы можете вызывать его, ссылаясь на имя класса InetAddress:

InetAddress iaLocal;
iaLocal = InetAddress.getLocalHost();

Создание объекта класса InetAddress для удаленного узла

В том случае, если вас интересует удаленный узел сети Internet или корпоративной сети Intranet, вы можете создать для него объект класса InetAddress с помощью методов getByName или getAllByName. Первый из них возвращает адрес узла, а второй - массив всех адресов IP, связанных с данным узлом. Если узел с указанным именем не существует, при выполнении методов getByName и getAllByName возникает исключение UnknownHostException.

Заметим, что методам getByName и getAllByName можно передавать не только имя узла, такое как, например, "sun.com", но и строку адреса IP в виде четырех десятичных чисел, разделенных точками.

После создания объекта класса InetAddress для локального или удаленного узла вы можете использовать другие методы этого класса.

Определение адреса IP

Метод getAddress возвращает массив из чеырех байт адреса IP объекта. Байт с нулевым индексом этого массива содержит старший байт адреса IP.

Метод toString возвращает текстовую строку, которая содержит имя узла, разделитель '/' и адрес IP в виде четырех десятичных чисел, разделенных точками.

Определение имени узла

С помощью метода getHostName вы можете определить имя узла, для которого был создан объект класса InetAddress.

Сравнение адресов IP

И, наконец, метод equals предназначен для сравнения адресов IP как объектов класса InetAddress.


Адрес URL
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Универсальный адрес ресурсов URL

Назад Вперед

Адрес IP позволяет идентифицировать узел, однако его недостаточно для идентификации ресурсов, имеющихся на этом узле, таких как работающие приложения или файлы. Причина очевидна - на узле, имеющем один адрес IP, может существовать много различных ресурсов.

Для ссылки на ресурсы сети Internet применяется так называемый универсальный адрес ресуросв URL (Universal Resource Locator). В общем виде этот адрес выглядит следующим образом:

[protocol]://host[:port][path]

Строка адреса начинаетс с протокола protocol, который должен быть использован для доступа к ресурсу. Документы HTML, например, передаются из сервера Web удаленным пользователям с помощью протокола HTTP. Файловые серверы в сети Internet работают с протоколом FTP.

Для ссылки на сетевые ресурсы через протокол HTTP используется следующая форма универсального адреса ресурсов URL:

http://host[:port][path]

Параметр host обязательный. Он должен быть указан как доменный адрес или как адрес IP (в виде четырех десятичных чисел). Например:

http://www.sun.com
http://157.23.12.101

Необязательный параметр port задает номер порта для работы с сервером. По умолчанию для протокола HTTP используется порт с номером 80, однако для специализированных серверов Web это может быть и не так.

Номер порта идентифицирует программу, работающую в узле сети TCP/IP и взаимодействующую с другими программами, расположенными на том же или на другом узле сети. Если вы разрабатываете программу, передающую данные через сеть TCP/IP с использованием, например, интерфейса сокетов Windows Sockets, то при создании канала связи с уделенным компьютером вы должны указать не только адрес IP, но и номер порта, который будет использован для передачи данных.

Ниже мы показали, как нужно указывать в адресе URL номер порта:

http://www.myspecial.srv/:82

Теперь займемся параметром path, определяющем путь к объекту.

Обычно любой сервер Web или FTP имеет корневой каталог, в котором расположены подкаталоги. Как в корневом каталоге, так и в подкаталогах сервера Web могут находиться документы HTML, двоичные файлы, файлы с графическими изображениями, звуковые и видео-файлы, расширения сервера в виде программ CGI или библиотек динамической компоновки, дополняющих возможности сервера.

Если в качестве адреса URL указать навигатору только доменное имя сервера, сервер перешлет навигатору свою главную страницу. Имя файла этой страницы зависит от сервера. Большинство серверов на базе операционной системы UNIX посылают по умолчанию файл документа с именем index.html. Другие серверы Web могут использовать для этой цели имя default.htm или какое-нибудь еще, определенное при установке сервера, например, home.html или home.htm.

Для ссылки на конкретный документ HTML или на файл любого другого объекта необходимо указать в адресе URL его путь, включающий имя файла, например:

http://www.glasnet.ru/~frolov/index.html
http://www.dials.ccas.ru/frolov/home.htm

Корневой каталог сервера Web обозначается символом /. В спецификации протокола HTTP сказано, что если путь не задан, то используется корневой каталог.


Класс URL
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Класс URL в библиотеке классов Java

Назад Вперед

Для работы с ресурсами, заданными своими адресами URL, в библиотеке классов Java имеется очень удобный и мощный класс с названием URL. Простота создания сетевых приложений с использованием этого класса в значительной степени опровергает общераспространенное убеждение в сложности сетевого программирования. Инкапсулируя в себе достаточно сложные процедуры, класс URL предоставляет в распоряжение программиста небольшой набор простых в использовании конструкторов и методов.

Конструкторы класса URL

Сначала о конструкторах. Их в классе URL имеется четыре штуки.

public URL(String spec);

Первый из них создает объект URL для сетевого ресурса, адрес URL которого передается конструктору в виде текстовой строки через единственный параметр spec:

public URL(String spec);

В процессе создания объекта проверяется заданный адрес URL, а также наличие указанного в нем ресурса. Если адрес указан неверно или заданный в нем ресурс отсутствует, возникает исключение MalformedURLException. Это же исключение возникает при попытке использовать протокол, с которым данная система не может работать.

Второй вариант конструктора класса URL допускает раздельное указание протокола, адреса узла, номера порта, а также имя файла:

public URL(String protocol,
  String host, int port, String file);

Третий вариант предполагает использование номера порта, принятого по умолчанию:

public URL(String protocol,
  String host, String file);

Для протокола HTTP это порт с номером 80.

И, наконец, четвертый вариант конструктора допускает указание контекста адреса URL и строки адреса URL:

public URL(URL context, String spec);

Строка контекста позволяет указывать компоненты адреса URL, отсустсвующие в строке spec, такие как протокол, имя узла, файла или номер порта.

Методы класса URL

Рассмотрим самые интересные методы, определенные в классе URL.

Метод openStream

Метод openStream позволяет создать входной поток для чтения файла ресурса, связанного с созданным объектом класса URL:

public final InputStream openStream();

Для выполнения операции чтения из созданного таким образом потока вы можете использовать метод read, определенный в классе InputStream (любую из его разновидностей).

Данную пару методов (openStream из класса URL и read из класса InputStream) можно применить для решения задачи получения содержимого двоичного или текстового файла, хранящегося в одном из каталогов сервера Web. Сделав это, обычное приложение Java или аплет может выполнить локальную обработку полученного файла на компьютере удаленного пользователя.

Метод getContent

Очень интересен метод getConten. Этот метод определяет и получает содержимое сетевого ресурса, для которого создан объект URL:

public final Object getContent();

Практически вы можете использовать метод getContent для получения текстовых файлов, расположенных в сетевых каталогах.

К сожалению, данный метод непригоден для получения документов HTML, так как для данного ресурса не определен обработчик соедржимого, предназначенный для создания объекта. Метод getContent не способен создать объект ни из чего другого, кроме текстового файла.

Данная проблема, тем не менее, решается очень просто - достаточно вместо метода getContent использовать описанную выше комбинацию методов openStream из класса URL и read из класса InputStream.

Метод getHost

С помощью метода getHost вы можете определить имя узла, соответствующего данному объекту URL:

public String getHost();

Метод getFile

Метод getFile позволяет получить информацию о файле, связанном с данным объектом URL:

public String getFile();

Метод getPort

Метод getPortt предназначен для определения номера порта, на котором выполняется связь для объекта URL:

public int getPort();

Метод getProtocol

С помощью метода getProtocol вы можете определить протокол, с использованием которого установлено соединение с ресурсом, заданным объектом URL:

public String getProtocol();

Метод getRef

Метод getRef возвращает текстовую строку ссылки на ресурс, соответствующий данному объекту URL:

public String getRef();

Метод hashCode

Метод hashCode возвращает хэш-код объекта URL:

public int hashCode();

Метод sameFile

С помощью метода sameFile вы можете определить, ссылаются ли два объекта класса URL на один и тот же ресурс, или нет:

public boolean sameFile(URL other);

Если объекты ссылаются на один и тот же ресурс, метод sameFile возвращает значение true, если нет - false.

Метод equals

Вы можете использовать метод equals для определения идентичности адресов URL, заданных двумя объектами класса URL:

public boolean equals(Object obj);

Если адреса URL идентичны, метод equals возвращает значение true, если нет - значение false.

Метод toExternalForm

Метод toExternalForm возвращает текстовую строку внешнего представления адреса URL, определенного данным объектом класса URL:

public String toExternalForm();

Метод toString

Метод toString возвращает текстовую строку, представляющую данный объект класса URL:

public String toString();

Метод openConnection

Метод openConnection предназначен для создания канала между приложением и сетевым ресурсом, представленным объектом класса URL:

public URLConnection openConnection();

Если вы создаете приложение, которое позволяет читать из каталогов сервера Web текстовые или двоичные файлы, можно создать поток методом openStream или получить содержимое текстового ресурса методом getContent.

Однако есть и другая возможность. Вначале вы можете создать канал, как объект класса URLConnection, вызвав метод openConnection, а затем создать для этого канала входной поток, воспользовавшись методом getInputStream, определенным в классе URLConnection. Такая методика позволяет определить или установить перед созданием потока некоторые характеристики канала, например, задать кэширование.

Однако самая интересная возможность, которую предоставляет этот метод, заключается в организации взаимодействия приложения Java и сервера Web.


Сокеты
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Передача данных с использованием сокетов

Назад Вперед

В библиотеке классов Java есть очень удобное средство, с помощью которых можно организовать взаимодействие между приложениями Java и аплетами, работающими как на одном и том же, так и на разных узлах сети TCP/IP. Это средство, родившееся в мире операционной системы UNIX, - так называемые сокеты (sockets).

Что такое сокеты?

Вы можете представить себе сокеты в виде двух розеток, в которые включен кабель, предназначенный для передачи данных через сеть. Переходя к компьютерной терминологии, скажем, что сокеты - это программный интерфейс, предназначенный для передачи данных между приложениями.

Прежде чем приложение сможет выполнять передачу аили прием данных, оно должно создать сокет, указав при этом адрес узла IP, номер порта, через который будут передаваться данные, и тип сокета.

С адресом узла IP вы уже сталкивались. Номер порта служит для идентификации приложения. Заметим, что существуют так называемые "хорошо известные" (well known) номера портов, зарезервированные для различных приложений. Например, порт с номером 80 зарезервирован для использования серверами Web при обмене данными через протокол HTTP.

Что же касается типов сокетов, то их два - потоковые и датаграммные.

С помощью потоковых сокетов вы можете создавать каналы передачи данных между двумя приложениями Java в виде потоков, которые мы уже рассматривали во второй главе. Потоки могут быть входными или выходными, обычными или форматированными, с использованием или без использования буферизации. Скоро вы убедитесь, что организовать обмен данными между приложениями Java с использованием потоковых сокетов не труднее, чем работать через потоки с обычными файлами.

Заметим, что потоковые сокеты позволяют передавать данные только между двумя приложениями, так как они предполагают создание канала между этими приложениями. Однако иногда нужно обеспечить взаимодействие нескольких клиентских приложений с одним серверным или нескольких клиентских приложений с несколькими серверными приложениями. В этом случае вы можете либо создавать в серверном приложении отдельные задачи и отдельные каналы для каждого клиентского приложения, либо воспользоваться датаграммными сокетами. Последние позволяют передавать данные сразу всем узлам сети, хотя такая возможность редко используется и часто блокируется администраторами сети.

Для передачи данных через датаграммные сокеты вам не нужно создавать канал - данные посылаются непосредственно тому приложению, для которого они предназначены с использованием адреса этого приложения в виде сокета и номера порта. При этом одно клиентское приложение может обмениваться данными с несколькими серверными приложениями или наоборот, одно серверное приложение - с несколькими клиентскими.

К сожалению, датаграммные сокеты не гарантируют доставку передаваемых пакетов данных. Даже если пакеты данных, передаваемые через такие сокеты, дошли до адресата, не гарантируется, что они будут получены в той же самой последовательности, в которой были переданы. Потоковые сокеты, напротив, гарантируют доставку пакетов данных, причем в правильной последовательности.

Причина отстутствия гарантии доставки данных при использовании датаграммных сокетов заключается в использовании такими сокетами протокола UDP, который, в свою очередь, основан на протоколе с негарантированной доставкой IP. Потоковые сокеты работают через протокол гарантированной доставки TCP.


Потоковые сокеты
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Работа с потоковыми сокетами

Назад Вперед

Как мы уже говорили, интерфейс сокетов позволяет передавать данные между двумя приложениями, работающими на одном или разных узлах сети. В процессе создания канала передачи данных одно из этих приложений выполняет роль сервера, а другое - роль клиента. После того как канал будет создан, приложения становятся равноправными - они могут передавать друг другу данные симметричным образом.

Рассмотрим этот процесс в деталях.

Инициализация сервера

Вначале мы рассмотрим действия приложения, которое на момент инициализации является сервером.

Первое, что должно сделать серверное приложение, это создать объект класса ServerSocket, указав конструктору этого класса номер используемого порта:

ServerSocket ss;
ss = new ServerSocket(9999);

Заметим, что объект класса ServerSocket вовсе не является сокетом. Он предназначен всего лишь для установки канала связи с клиентским приложением, после чего создается сокет класса Socket, пригодный для передачи данных.

Установка канала связи с клиентским приложением выполняется при помощи метода accept, определенного в классе ServerSocket:

Socket s;
s = ss.accept();

Метод accept приостанавливает работу вызвавшего потока до тех пор, пока клиентское приложение не установит канал связи с сервером. Если ваше приложение однопоточное, его работа будет блокирована до момента установки канала связи. Избежать полной блокировки приложения можно, если выполнять создание канала передачи данных в отдельном потоке.

Как только канал будет создан, вы можете использовать сокет сервера для образования входного и выходного потока класса InputStream и OutputStream, соответственно:

InputStream is;
OutputStream os;
is = s.getInputStream();
os = s.getOutputStream();

Эти потоки можно использовать таким же образом, что и потоки, связанные с файлами.

Обратите также внимание на то, что при создании серверного сокета мы не указали адрес IP и тип сокета, ограничившись только номером порта.

Что касается адреса IP, то он, очевидно, равен адресу IP узла, на котором запущено приложение сервера. В классе ServerSocket определен метод getInetAddress, позволяющий определить этот адрес:

public InetAddress getInetAddress();

Тип сокета указывать не нужно, так как для работы с датаграммными сокетами предназначен класс DatagramSocket, который мы рассмотрим позже.

Инициализация клиента

Процесс инициализации клиентского приложения выглядит весьма просто. Клиент должен просто создать сокет как объект класса Socket, указав адрес IP серверного приложения и номер порта, используемого сервером:

Socket s;
s = new Socket("localhost",9999);

Здесь в качестве адреса IP мы указали специальный адрес localhost, предназначенный для тестирования сетевых приложений, а в качестве номера порта - ззначение 9999, использованное сервером.

Теперь можно создавать входной и выходной потоки. На стороне клиента эта операция выполняется точно также, как и на стороне сервера:

InputStream is;
OutputStream os;
is = s.getInputStream();
os = s.getOutputStream();

Передача данных между клиентом и сервером

После того как серверное и клиентское приложения создали потоки для приема и передачи данных, оба этих приложения могут читать и писать в канал данных, вызывая методы read и write, определенные в классах InputStream и OutputStream.

Ниже мы представили фрагмент кода, в котором приложение вначале читает данные из входного потока в буфер buf, а затем записывает прочитанные данные в выходной поток:

byte buf[] = new byte[512];
int lenght;
lenght = is.read(buf);
os.write(buf, 0, lenght);
os.flush();

На базе потоков класса InputStream и OutputStream вы можете создать буферизованные потоки и потоки для передачи форматированных данных, о которых мы рассказывали раньше.

Завершение работы сервера и клиента

После завершения передачи данных вы должны закрыть потоки, вызвав метод close:

is.close();
os.close();

Когда канал передачи данных больше не нужен, сервер и клиент должны закрыть сокет, вызвав метод close, определенный в классе Socket:

s.close();

Серверное приложение, кроме того, должно закрыть соединение, вызвав метод close для объекта класса ServerSocket:

ss.close();


Класс Socket
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Класс Socket

Назад Вперед

После краткого введения в сокеты приведем описание наиболее интересных конструкторов и методов класса Socket.

Конструкторы класса Socket

Чаще всего для создания сокетов в клиентских приложениях вы будете использовать один из двух конструкторов, прототипы которых приведены ниже:

public Socket(String host,int port);
public Socket(InetAddress address,int port);

Первый из этих конструкторов позволяет указывать адрес серверного узла в виде текстовой строки, второй - в виде ссылки на объект класса InetAddress. Вторым параметром задается номер порта, с использованием которого будут передаваться данные.

В классе Socket определена еще одна пара конструкторов, которая, однако не рекомендуется для использования:

public Socket(String host,
   int port, boolean stream);
public Socket(InetAddress address,
   int port, boolean stream);

В этих конструкторах последний параметр определяет тип сокета. Если этот параметр равен true, создается потоковый сокет, а если false - датаграммный. Заметим, что для работы с датаграммными сокетами следует использовать класс DatagramSocket.

Методы класса Socket

Перечислим наиболее интересные, на наш взгляд, методы класса Socket.

Прежде всего, это методы getInputStream и getOutputStream, предназначенные для создания входного и выходного потока, соответственно:

public InputStream getInputStream();
public OutputStream getOutputStream();

Эти потоки связаны с сокетом и должны быть использованы для передачи данных по каналу связи.

Методы getInetAddress и getPort позволяют определить адрес IP и номер порта, связанные с данным сокетом (для удаленного узла):

public InetAddress getInetAddress();
public int getPort();

Метод getLocalPort возвращает для данного сокета номер локального порта:

public int getLocalPort();

После того как работа с сокетом завершена, его необходимо закрыть методом close:

public void close();

И, наконец, метод toString возвращает текстовую строку, представляющую сокет:

public String toString();


Датаграммные сокеты
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Использование датаграммных сокетов

Назад Вперед

Как мы уже говорили, датаграммные сокеты не гарантируют доставку пакетов данных. Тем не менее, они работают быстрее потоковых и обеспечивают возможность широковещательной расслыки пакетов данных одновременно всем узлам сети. Последняя возможность используется не очень широко в сети Internet, однако в корпоративной сети Intranet вы вполне можете ей воспользоваться.

Для работы с датаграммными сокетами приложение должно создать сокет на базе класса DatagramSocket, а также подготовить объект класса DatagramPacket, в который будет записан принятый от партнера по сети блок данных.

Канал, а также входные и выходные потоки создавать не нужно. Данные передаются и принимаются методами send и receive, определенными в классе DatagramSocket.

Класс DatagramSocket

Рассмотрим конструкторы и методы класса DatagramSocket, предназначенного для создания и использования датаграммных сокетов.

В классе DatagramSocket определены два конструктора, прототипы которых представлены ниже:

public DatagramSocket(int port);
public DatagramSocket();

Первый из этих конструкторов позволяет определить порт для сокета, второй предполагает использование любого свободного порта.

Обычно серверные приложения работают с использованием какого-то заранее определенного порта, номер которого известен клиентским приложениям. Поэтому для серверных приложений больше подходит первый из приведенных выше конструкторов.

Клиентские приложения, напротив, часто применяют любые свободные на локальном узле порты, поэтому для них годится конструктор без параметров.

Кстати, с помощью метода getLocalPort приложение всегда может узнать номер порта, закрепленного за данным сокетом:

public int getLocalPort();

Прием и передача данных на датаграммном сокете выполняется с помощью методов receive и send, соответственно:

public void receive(DatagramPacket p);
public void send(DatagramPacket p);

В качестве параметра этим методам передается ссылка на пакет данных (соответственно, принимаемый и передаваемый), определенный как объект класса DatagramPacket. Этот класс будет рассмотрен позже.

Еще один метод в классе DatagramSocket, которым вы будете пользоваться, это метод close, предназначенный для закрытия сокета:

public void close();

Напомним, что сборка мусора в Java выполняется только для объектов, находящихся в оперативной памяти. Такие объекты, как потоки и сокеты, вы должны закрывать после использования самостоятельно.

Класс DatagramPacket

Перед тем как принимать или передавать данные с использованием методов receive и send вы должны подготовить объекты класса DatagramPacket. Метод receive запишет в такой объект принятые данные, а метод send - перешлет данные из объекта класса DatagramPacket узлу, адрес которого указан в пакете.

Подготовка объекта класса DatagramPacket для приема пакетов выполняется с помощью следующего конструктора:

public DatagramPacket(byte ibuf[],
 int ilength);

Этому конструктору передается ссылка на массив ibuf, в который нужно будет записать данные, и размер этого массива ilength.

Если вам нужно подготовить пакет для передачи, воспользуйтесь конструктором, который дополнительно позволяет задать адрес IP iaddr и номер порта iport узла назначения:

public DatagramPacket(byte ibuf[],
  int ilength,
  InetAddress iaddr, int iport);

Таким образом, информация о том, в какой узел и на какой порт необходимо доставить пакет данных, хранится не в сокете, а в пакете, то есть в объекте класса DatagramPacket.

Помимо только что описанных конструкторов, в классе DatagramPacket определены четыре метода, позволяющие получить данные и информацию об адресе узла, из которого пришел пакет, или для которого предназначен пакет.

Метод getData возвращает ссылку на массив данных пакета:

public byte[] getData();

Размер пакета, данные из которого хранятся в этом массиве, легко определить с помощью метода getLength:

public int getLength();

Методы getAddress и getPort позволяют определить адрес и номер порта узла, откуда пришел пакет, или узла, для которого предназначен пакет:

public InetAddress getAddress();
public int getPort();

Если вы создаете клиент-серверную систему, в которой сервер имеет заранее известный адрес и номер порта, а клиенты - произвольные адреса и различные номера портов, то после получения пакета от клиента сервер может определить с помощью методов getAddress и getPort адрес клиента для установления с ним связи.

Если же адрес сервера неизвестен, клиент может посылать широковещательные пакеты, указав в объекте класса DatagramPacket адрес сети. Такая методика обычно используется в локальных сетях.

Как указать адрес сети?

Напомним, что адрес IP состоит из двух частей - адреса сети и адреса узла. Для разделения компонент 32-разрядного адреса IP используется 32-разрядная маска, в которой битам адреса сети соответствуют единицы, а битам адреса узла - нули.

Например, адрес узла может быть указан как 193.24.111.2. Исходя из значения старшего байта адреса, это сеть класса С, для которой по умолчанию используется маска 255.255.255.0. Следовательно, адрес сети будет такой: 193.24.111.0.


Связь с Web
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Связь приложений Java с расширениями сервера Web

Назад Вперед

Итак, мы расказали вам, как приложения Java могут получать с сервера Web для обработки произвольные файлы, а также как они могут передавать данные друг другу с применением потоковых или датаграммных сокетов.

Однако наиболее впечатляющие возможности открываются, если организовать взаимодействие между приложением Java и расширением сервера Web, таким как CGI или ISAPI. В этом случае приложения или аплеты Java могли бы посылать произвольные данные расширению сервера Web для обработки, а затем получать результат этой обработки в виде файла.

Взаимодействие приложения Java и расширения сервера Web

Методика организации взаимодействия приложений Java и расширений сервера Web основана на применении классов URL и URLConnection.

Приложение Java, желающее работать с расширением сервера Web, создает объект класса URL для программы расширения (то есть для исполняемого модуля расширения CGI или библиотеки динамической компоновки DLL расширения ISAPI).

Далее приложение получает ссылку на канал передачи данных с этим расширением как объекта класса URLConnection. Затем, пользуясь методами getOutputStream и getInputStream из класса URLConnection, приложение создает с расширением сервера Web выходной и входной канал передачи данных.

Когда данные передаются приложением в выходной канал, созданный подобным образом, он попадает в стандартный поток ввода приложения CGI, как будто бы данные пришли методом POST из формы, определенной в документе HTML.

Обработав полученные данные, расширение CGI записывает их в свой стандартный выходной поток, после чего эти данные становятся доступны приложению Java через входной поток, открытый методом getInputStream класса URLConnection.

На рис. 1 показаны потоки данных для описанной выше схемы взаимодействия приложения Java и расширения сервреа Web с интерфейсом CGI.

pic01.gif (4413 bytes)

Рис. 1. Взаимодействие приложения Java с расширением сервера Web на базе интерфейса CGI

Расширения ISAPI работают аналогично, однако они получают данные не из стандратного входного потока, а с помощью вызова специально предназначенной для этого функции интерфейса ISAPI. Вместо стандартного потока вывода также применяется специальная функция.

Класс URLConnection

Напомним, что в классе URL, рассмотренном нами в начале этой главы, мы привели прототип метода openConnection, возвращающий для заданного объекта класса URL ссылку на объект URLConnection:

public URLConnection openConnection();

Что мы можем получить, имея ссылку на этот объект?

Прежде всего, пользуясь этой ссылкой, мы можем получить содержимое объекта, адресуемое соответствующим объектом URL, методом getContent:

public Object getContent();

Заметим, что метод с таким же названием есть и в классе URL. Поэтому если все, что вы хотите сделать, это получение содержимое файла, адресуемое объектом класса URL, то нет никакой необходимости обращаться к классу URLConnection.

Метод getInputStream позволяет открыть входной поток данных, с помощью которого можно считать файл или получить данные от расширения сервера Web:

public InputStream getInputStream();

В классе URLConnection определен также метод getOutputStream, позволяющий открыть выходной поток данных:

public OutputStream getOutputStream();

Не следует думать, что этот поток можно использовать для записи файлов в каталоги сервера Web. Однако для этого потока есть лучшее применение - с его помощью можно передать данные расширению сервера Web.

Рассмотрим еще несколько полезных методов, определенных в классе URLConnection.

Метод connect предназначен для установки соединения с объектом, на который ссылается объект класса URL:

public abstract void connect();

Перед установкой соединения приложение может установить различные параметры соединения. Некоторые из методов, предназначенных для этого, приведены ниже:

  • setDefaultUseCaches

Включение или отключение кэширования по умолчанию

public void setDefaultUseCaches(
  boolean defaultusecaches);
  • setUseCaches

Включение или отключение кэширования

public void setUseCaches(boolean usecaches);
  • setDoInput

Возможность использования потока для ввода

public void setDoInput(boolean doinput);
  • setDoOutput

Возможность использования потока для вывода

public void setDoOutput(boolean dooutput);
  • setIfModifiedSince

Установка даты модификации документа

public void setIfModifiedSince(
  long ifmodifiedsince);

В классе URLConnection есть методы, позволяющие определить значения параметров, установленных только что описанными методами:

public boolean getDefaultUseCaches();
public boolean getUseCaches();
public boolean getDoInput();
public boolean getDoOutput();
public long getIfModifiedSince();

Определенный интерес могут представлять методы, предназначенные для извлечения информации из заголовка протокола HTTP:

  • getContentEncoding

Метод возвращает содержимое заголовка content-encoding (кодировка ресурса, на который ссылается URL)

public String getContentEncoding();
  • getContentLength

Метод возвращает содержимое заголовка content-length (размер документа)

public int getContentLength();
  • getContentType

Метод возвращает содержимое заголовка content-type (тип содержимого)

public String getContentType();
  • getDate

Метод возвращает содержимое заголовка date (дата посылки ресурса в секундах с 1 января 1970 года)

public long getDate();
  • getLastModified

Метод возвращает содержимое заголовка last-modified (дата изменения ресурса в секундах с 1 января 1970 года)

public long getLastModified();
  • getExpiration

Метод возвращает содержимое заголовка expires (дата устаревания ресурса в секундах с 1 января 1970 года)

public long getExpiration();

Другие методы, определенные в классе URLConnection, позволяют получить все заголовки или заголовки с заданным номером, а также другую информацию о соединении. При необходимости вы найдете описание этих методов в справочной системе Java WorkShop.


Аплет ShowChart
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Аплет ShowChart

Назад Вперед

Попробуем теперь на практике применить технологию передачи файлов из каталога сервера Web в аплет для локальной обработки. Наше следующее приложение с названием ShowChart получает небольшой текстовый файл с исходными данными для построения круговой диаграммы, содержимое которого представлено ниже:

10,20,5,35,11,10,3,6,80,10,20,5,35,11,10,3,6,80

В этом файле находятся численные значения углов для отдельных секторов диаграммы, причем сумма этих значений равна 360 градусам. Наш аплет принимает этот файл через сеть и рисует круговую диаграмму, показанную на рис. 2.

pic02.gif (3920 bytes)

Рис. 2. Круговая диаграмма, построенная на базе исходных данных, полученных через сеть

Файл исходных данных занимает всего 49 байт, поэтому он передается по сети очень быстро. Если бы мы передавали графическое изображение этой диаграммы, статическое или динамическое, подготовленное, например, расширением сервера CGI или ISAPI, объем передаваемых по сети данных был бы намного больше.

Исходные тексты аплета ShowChart

Исходный текст приложения ShowChart приведен в листинге 1.

Листинг 1. Файл ShowChart.java

import java.applet.*;
import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;
public class ShowChart extends Applet
{
  URL SrcURL;
  Object URLContent;
  int errno = 0;
  String str;
  byte buf[] = new byte[200];
  public String getAppletInfo()
  {
    return "Name: ShowChart";
  }
  public void init()
  {
    try
    {
      SrcURL = new URL(
        "http://frolov/chart.txt");
      try
      {
        InputStream is = SrcURL.openStream();
        is.read(buf);
        str = new String(buf, 0);
      }
      catch (IOException ioe)
      {
        showStatus("read exception");
        errno = 1;
      }
    }
    catch (MalformedURLException uex)
    {
      showStatus(
        "MalformedURLException exception");
      errno = 2;
    }
  }
  public void paint(Graphics g)
  {
    Integer AngleFromChart = new Integer(0);
    int PrevAngle = 0;
    int rColor, gColor, bColor;
    Dimension dimAppWndDimension = getSize();

    g.setColor(Color.yellow);
    g.fillRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    showStatus(str);
    StringTokenizer st =
       new StringTokenizer(str, ",\r\n");
    while(st.hasMoreElements())
    {
      rColor = (int)(255 * Math.random());
      gColor = (int)(255 * Math.random());
      bColor = (int)(255 * Math.random());
      g.setColor(new Color(rColor,
         gColor, bColor));
      String angle =
        (String)st.nextElement();
      AngleFromChart = new Integer(angle) ;
      g.fillArc(0, 0, 200, 200,
        PrevAngle,
        AngleFromChart.intValue());
      PrevAngle += AngleFromChart.intValue();
    }
  }
}

Исходный текст документа HTML, созданного автоматически для нашего аплета, представлен в листинге 2.

Листинг 2. Файл ShowChart.tmp.html

<applet
  name="ShowChart"
  code="ShowChart"
  codebase=
  "file:/e:/Sun/Articles/vol12/src/ShowChart"
  width="200"
  height="200"
  align="Top"
  alt="If you had a java-enabled browser,
 you would see an applet here.">
  <hr>If your browser recognized
the applet tag,
you would see an applet here.
  <hr>
</applet>

Описание исходного текста аплета ShowChart

Аплет ShowChart получает содержимое файла исходных данных для построения круговой диаграммы с помощью класса URL. Как вы увидите, для получения содержимого этого файла оно создает поток ввода явным образом.

Поля класса ShowChart

В классе ShowChart определены пять полей.

URL SrcURL;
Object URLContent;
int errno = 0;
String str;
byte buf[] = new byte[200];

Поле SrcURL класса URL хранит адрес URL файла исходных данных для круговой диаграммы. В поле URLContent типа Object будет переписано содержимое этого файла. В поле errno хранится текущий код ошибки, если она возникла, или нулевое значение, если все операции были выполнены без ошибок.

Поле str хранит принятую строку, которая предварительно записывается во временный буфер buf.

Метод init

Во время инициализации метод init создает объект класса URL для файла исходных данных:

SrcURL = new URL("http://frolov/chart.txt");

Здесь для упрощения исходного текста мы указали адрес URL файла данных непосредственно в программе, однако вы можете передать этот адрес аплету через параметр в документе HTML.

Далее для нашего объекта URL мы создаем поток ввода и получаем содержимое файла (то есть исходные данные для построения диаграммы):

InputStream is = SrcURL.openStream();
is.read(buf);

Принятые данные записываются в буфер buf и затем преобразуются к типу String с помощью соответствующего конструктора:

str = new String(buf, 0);

Если при создании объекта класса URL возникло исключение, метод init записывает в поле errno код ошибки, равный 2, записывая при этом в строку состояния браузера сообщение "MalformedURLException exception".

В том случае, когда объект класса URL создан успешно, а исключение возникло в процессе чтения содержимого файла, в поле errno записывается значение 1, а в строку состояния браузера - сообщение "read exception".

Метод paint

После раскрашивания фона окна аплета и рисования вокруг него рамки метод paint приступает к построению круговой диаграммы. Принятые данные отображаются в строке состояния браузера:

showStatus(sChart);

Далее создается разборщик строки исходных данных:

StringTokenizer st =
  new StringTokenizer(sChart, ",\r\n");

В качестве разделителей для этого разборщика указывается запятая, символ возврата каретки и перевода строки.

Рисование секторов диаграммы выполняется в цикле, условием выхода из которого является завершение разбора строки исходных данных:

while(st.hasMoreElements())
{
  . . .
}

Для того чтобы секторы диаграммы не сливались, они должны иметь разный цвет. Цвет сектора можно было бы передавать вместе со значением угла через файл исходных данных, однако мы применили более простой способ раскаршивания секторов - в случайные цвета. Мы получаем случайные компоненты цвета сектора, а затем выбираем цвет в контекст отображения:

rColor = (int)(255 * Math.random());
gColor = (int)(255 * Math.random());
bColor = (int)(255 * Math.random());
g.setColor(new Color(rColor,
   gColor, bColor));

С помощью метода nextElement мы получаем очередное значение угла сектора и сохраняем его в переменной angle:

String angle = (String)st.nextElement();

Далее с помощью конструктора класса Integer это значение преобразуется в численное:

AngleFromChart = new Integer(angle);

Рисование сектора круговой диаграммы выполняется с помощью метода fillArc:

g.fillArc(0, 0, 200, 200,
  PrevAngle, AngleFromChart.intValue());

В качестве начального значения угла сектора используется значение из переменной PrevAngle. Сразу после инициализации в эту переменную записывается нулевое значение.

Конечный угол сектора задается как AngleFromChart.intValue(), то есть указывается значение, полученное из принятого по сети файла исходных данных.

После завершения рисования очередного сектора круговой диаграммы начальное значение PrevAngle увеличивается на величину угла нарисованного сектора:

PrevAngle += AngleFromChart.intValue();


Приложения SocketServ и SocketClient
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Приложения SocketServ и SocketClient

Назад Вперед

В качестве примера мы приведем исходные тексты двух приложений Java, работающих с потоковыми сокетами. Одно из этих приложений называется SocketServ и выполняет роль сервера, второе называется SocketClient и служит клиентом.

Приложение SocketServ выводит на консоль строку "Socket Server Application" и затем переходит в состояние ожидания соединения с клиентским приложением SocketClient.

Приложение SocketClient устанавливает соединение с сервером SocketServ, используя потоковый сокет с номером 9999 (этот номер выбран нами произвольно). Далее клиентское приложение выводит на свою консоль приглашение для ввода строк. Введенные строки отображаются на консоли и передаются серверному приложению. Сервер, получив строку, отображает ее в своем окне и посылает обратно клиенту. Клиент выводит полученную от сервера строку на консоли.

Когда пользователь вводит строку "quit", цикл ввода и передачи строк завершается.

Весь процесс показан на рис. 3 и 4.

pic03.gif (4444 bytes)

Рис. 3. Окно клиентского приложения

pic04.gif (3495 bytes)

Рис. 4. Окно серверного приложения

Здесь в окне клиентского приложения мы ввели несколько строк, причем последняя строка была строкой "quit", завершившая работу приложений.

Исходный текст серверного приложения SocketServ

Исходный текст серверного приложения SocketServ приведен в листинге 3.

Листинг 3. Файл SocketServ.java

import java.io.*;
import java.net.*;
import java.util.*;
public class SocketServ
{
  public static void main(String args[])
  {
    byte bKbdInput[] = new byte[256];
    ServerSocket ss;
    Socket s;
    InputStream is;
    OutputStream os;
    try
    {
      System.out.println(
        "Socket Server Application");
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
    try
    {
      ss = new ServerSocket(9999);
      s = ss.accept();
      is = s.getInputStream();
      os = s.getOutputStream();
      byte buf[] = new byte[512];
      int lenght;
      while(true)
      {
        lenght = is.read(buf);
        if(lenght == -1)
          break;
        String str = new String(buf, 0);
        StringTokenizer st;
        st   = new StringTokenizer(
           str, "\r\n");
        str = new String(
          (String)st.nextElement());
        System.out.println(">  " + str);
        os.write(buf, 0, lenght);
        os.flush();
      }
      is.close();
      os.close();
      s.close();
      ss.close();
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
    try
    {
      System.out.println(
        "Press <Enter> to terminate
 application...");
      System.in.read(bKbdInput);
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
}

Описание исходного текста серверного приложения SocketServ

В методе main, получающем управление сразу после запуска приложения, мы определили несколько переменных.

Массив bKbdInput размером 256 байт предназначен для хранения строк, введенных при помощи клавиатуры.

В переменную ss класса ServerSocket будет записана ссылка на объект, предназначенный для установления канала связи через потоковый сокет (но не ссылка на сам сокет):

ServerSocket ss;

Ссылка на сокет, с использованием которого будет происходить передача данных, хранится в переменной с именем s класса Socket:

Socket s;

Кроме того, мы определили переменные is и os, соответственно, классов InputStream и OutputStream:

InputStream is;
OutputStream os;

В эти переменные будут записаны ссылки на входной и выходной поток данных, которые связаны с сокетом.

После отображения на консоли строки названия приложения, метод main создает объект класса ServerSocket, указывая конструктору номер порта 9999:

ss = new ServerSocket(9999);

Конструктор возвращает ссылку на объект, с использованием которого можно установить канал передачи данных с клиентом.

Канал устанавливается методом accept:

s = ss.accept();

Этот метод переводит приложение в состояние ожидания до тех пор, пока не будет установлен канал передачи данных.

Метод accept в случае успешного создания канала передачи данных возвращает ссылку на сокет, с применением которого нужно принимать и передавать данные.

На следующем этапе сервер создает входной и выходной потоки, вызывая для этого методы getInputStream и getOutputStream, соответственно:

is = s.getInputStream();
os = s.getOutputStream();

Далее приложение подготавливает буфер buf для приема данных и определяет переменную length, в которую будет записываться размер принятого блока данных:

byte buf[] = new byte[512];
int lenght;

Теперь все готово для запуска цикла приема и обработки строк от клиентского приложения.

Для чтения строки мы вызываем метод read применительно ко входному потоку:

lenght = is.read(buf);

Этот метод возвращает управление только после того, как все данные будут прочитаны, блокируя приложение на время своей работы. Если такая блокировка нежелательна, вам следует выполнять обмен данными через сокет в отдельной задаче.

Метод read возвращает размер принятого блока данных или -1, если поток исчерпан. Мы воспользовались этим обстоятельством для завершения цикла приема данных:

if(lenght == -1)
  break;

После завершения приема блока данных мы преобразуем массив в текстовую строку str класса String, удаляя из нее символ перевода строки, и отображаем результат на консоли сервера:

System.out.println(">  " + str);

Затем полученная строка отправляется обратно клиентскому приложению, для чего вызывается метод write:

os.write(buf, 0, lenght);

Методу write передается ссылка на массив, смещение начала данных в этом массиве, равное нулю, и размер принятого блока данных.

Для исключения задержек в передаче данных из-за накопления данных в буфере (при использовании буферизованных потоков) необходимо принудительно сбрасывать содержимое буфреа метдом flush:

os.flush();

И хотя в нашем случае мы не пользуемся буферизованными потоками, мы включили вызов этого метода для примера.

Теперь о завершающих действиях после прерывания цикла получения, отображения и передачи строк.

Наше приложение явням образом закрывает входной и выходной потоки данных, сокет, а также объект класса ServerSocket, с использованием которого был создан канал передачи данных:

is.close();
os.close();
s.close();
ss.close();

Исходный текст клиентского приложения SocketClient

Исходный текст клиентского приложения SocketClient приведен в листинге 4.

Листинг 4. Файл SocketClient.java

import java.io.*;
import java.net.*;
import java.util.*;
public class SocketClient
{
  public static void main(String args[])
  {
    byte bKbdInput[] = new byte[256];
    Socket s;
    InputStream is;
    OutputStream os;
    try
    {
      System.out.println(
        "Socket Client Application" +
        "\nEnter any string or" +
        " 'quit' to exit...");
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
    try
    {
      s = new Socket("localhost",9999);
      is = s.getInputStream();
      os = s.getOutputStream();
      byte buf[] = new byte[512];
      int length;
      String str;
      while(true)
      {
        length = System.in.read(bKbdInput);
        if(length != 1)
        {
          str = new String(bKbdInput, 0);
          StringTokenizer st;
          st   = new StringTokenizer(
            str, "\r\n");
          str = new String(
            (String)st.nextElement());
          System.out.println(">  " + str);
          os.write(bKbdInput, 0, length);
          os.flush();
          length = is.read(buf);
          if(length == -1)
            break;
          str = new String(buf, 0);
          st   = new StringTokenizer(
            str, "\r\n");
          str = new String(
              (String)st.nextElement());
          System.out.println(">> " + str);
          if(str.equals("quit"))
            break;
        }
      }
      is.close();
      os.close();
      s.close();
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
    try
    {
      System.out.println(
        "Press <Enter> to " +
         "terminate application...");
      System.in.read(bKbdInput);
    }
    catch(Exception ioe)
    {
      System.out.println(ioe.toString());
    }
  }
}

Описание исходного текста клиентского приложения SocketClient

Внутри метода main клиентского приложения SocketClient определены переменные для ввода строки с клавиатуры (массив bKbdInput), сокет s класса Socket для работы с сервером SocketServ, входной поток is и выходной поток os, которые связаны с сокетом s.

После вывода на консоль приглашающей строки клиентское приложение создает сокет, вызывая конструктор класса Socket:

s = new Socket("localhost",9999);

В процессе отладки мы запускали сервер и клиент на одном и том же узле, поэтому в качестве адреса сервера указана строка "localhost". Номер порта сервера SocketServ равен 9999, поэтому мы и передали конструктору это значение.

После создания сокета наше клиентское приложение создает входной и выходной потоки, связанные с этим сокетом:

is = s.getInputStream();
os = s.getOutputStream();

Теперь клиентское приложение готово обмениваться данными с сервером.

Этот обмен выполняется в цикле, условием завершения которого является ввод пользователем строки "quit".

Внутри цикла приложение читает строку с клавиатуры, записывая ее в массив bKbdInput:

length = System.in.read(bKbdInput);

Количество введенных символов сохраняется в переменной length.

Далее если пользователь ввел строку, а не просто нажал на клавишу <Enter>, эта строка отображается на консоли и передается серверу:

os.write(bKbdInput, 0, length);
os.flush();

Сразу после передачи сбрасывается буфер выходного потока.

Далее приложение читает ответ, посылаемый сервером, в буфер buf:

length = is.read(buf);

Напомним, что наш сервер посылает клиенту принятую строку в неизменном виде.

Если сервер закрыл канал, то метод read возвращает значение -1. В этом случае мы прерываем цикл ввода и передачи строк:

if(length == -1)
  break;

Если же ответ сервера принят успешно, принятые данные записываются в строку str, которая отображается на консоли клиента:

System.out.println(">> " + str);

Перед завершением своей работы клиент закрывает входной и выходной потоки, а также сокет, на котором выполнялась передача данных:

is.close();
os.close();
s.close();


Аплет Form
Сетевые приложения
Адрес IP
Адрес URL
Класс URL
Сокеты
Потоковые сокеты
Класс Socket
Датаграммные сокеты
Связь с Web
Аплет ShowChart
Приложения SocketServ и SocketClient
Аплет Form

Аплет Form

Назад Вперед

На примере аплета Form мы покажем, как приложения Java могут взаимодействовать с расширениями сервера Web, такими как программы CGI или приложения ISAPI.

В окне нашего аплета находится форма, содержащая два однострочных поля редактирования, кнопку и многострочное поле редактирования (рис. 5).

pic05.gif (4332 bytes)

Рис. 5. Окно аплета Form

Эта форма предназначена для добавления записей в базу данных, содержащую электронные почтовые адреса. Заполнив поля имени и адреса E-Mail, пользователь должен нажать кнопку Send. При этом введенная информация будет передана расширению сервера CGI, который запишет ее в базу данных, а затем отправит обратно аплету. Сохраненные записи, полученные от программы CGI, аплет FORM отобразит в многострочном поле редактирования, как это показано на рис. 5.

Исходные тексты аплета Form

Исходные тексты аплета Form представлены в листинге 5.

Листинг 5. Файл Form.java

import java.applet.*;
import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;
public class Form extends Applet
  implements Runnable
{
  private Thread m_store = null;
  TextField txtName;
  TextField txtEMail;
  TextArea  txta;
  Button btnGetText;
  public void init()
  {
    Label lbName;
    Label lbEMail;
    Label lbPress;
    lbName = new Label("Enter your name:");
    lbEMail = new Label(
      "Enter your E-Mail address:");
    add(lbName);
    txtName = new TextField("Your name", 40);
    add(txtName);
    add(lbEMail);
    txtEMail =
      new TextField("your@email", 40);
    add(txtEMail);
    btnGetText = new Button("Send!");
    add(btnGetText);
    txta = new TextArea(8, 65);
    add(txta);
    setBackground(Color.yellow);
  }
  public void paint(Graphics g)
  {
    setBackground(Color.yellow);
    Dimension dimAppWndDimension = getSize();
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
  }
  public boolean action(Event evt, Object obj)
  {
    Button btn;
    if(evt.target instanceof Button)
    {
      btn = (Button)evt.target;
      if(evt.target.equals(btnGetText))
      {
        startTransaction();
      }
      else
        return false;
      return true;
    }
    return false;
  }
  void startTransaction()
  {
    m_store = new Thread(this);
    m_store.start();
  }
  public void stop()
  {
    if (m_store != null)
    {
      m_store.stop();
      m_store = null;
    }
  }
  public void run()
  {
    URL u;
    URLConnection c;
    PrintStream ps;
    DataInputStream is;
    try
    {
      String szSourceStr =
        txtName.getText() +
    ", " + txtEMail.getText();
      String szReceived;
      String szURL =
      "http://frolov/scripts/store.exe";
      u = new URL(szURL);
      c = u.openConnection();
      ps = new PrintStream(
        c.getOutputStream());
      ps.println(szSourceStr);
      ps.close();
      is = new DataInputStream(
        c.getInputStream());
      szReceived = is.readLine();
      is.close();
      txta.appendText(szReceived + "\r\n");
      repaint();
    }
    catch (Exception ioe)
    {
      showStatus(ioe.toString());
      stop();
    }
  }
}

Исходный текст документа HTML, который был подготовлен для нас системой Java Workshop, мы немного отредактировали, изменив параметр CODEBASE (листинг 6).

Листинг 6. Файл Form.tmp.html

<applet name="Form"
  code="Form.class"
  codebase="http://frolov/"
  width="500"
  height="200"
  align="Top"
  alt="If you had a java-enabled browser,
 you would see an applet here.">
   <hr>If your browser
recognized the applet tag,
you would see an applet here.<hr>
</applet>

В этом параметре следует указать путь к каталогу, в котором располагается байт-код аплета.

Описание исходныех текстов аплета Form

При инициализации метод init создает все необходимые органы управления и добавляет их в окно аплета.

Когда пользователь заполняет форму и нажимает кнопку Send, обработчик соответствующего события вызывает метод startTransaction, запускающий процесс обмена данными с расширением сервера Web:

if(evt.target.equals(btnGetText))
{
  startTransaction();
}

Метод startTransaction, определенный в нашем приложении, создает и запускает на выполнение поток, который и будет взаимодействовать с программой CGI:

void startTransaction()
{
  m_store = new Thread(this);
  m_store.start();
}

При этом в качестве отдельного потока, работающего одновременно с кодом аплета, выступает метод run. Именно в нем сосредоточена вся логика обмена данными с сервером Web.

Так как в процессе взаимодействия могут возникать различные исключения, мы предусмотрели их обработку при помощи блока try-catch:

URL u;
URLConnection c;
PrintStream ps;
DataInputStream is;
try
{
  . . .
}
catch (Exception ioe)
{
  showStatus(ioe.toString());
  stop();
}

Название возникшего исключения будет отображено в строке состояния браузера.

Теперь о том, что делает метод run после получения управления.

Первым делом он извлекает из однострочных текстовых полей имя и электронный адрес, объединяя их и записывая полученную текстовую строку в поле szSourceStr:

String szSourceStr =
   txtName.getText() + ", " +
   txtEMail.getText();

В строке szURL находится адрес URL программы CGI:

String szURL =
  "http://frolov/scripts/store.exe";

В реальном приложении этот адрес необходимо передавать аплету через параметр. Мы использовали непосредственное кодирование только для упрощения исходного текста.

На следующем этапе метод run создает для программы CGI объект класса URL и открывает с ним соединение:

u = new URL(szURL);
c = u.openConnection();

Пользуясь этим соединением, метод run создает форматированный поток вывода, записывает в него строку имени и электронного адреса, а затем закрывает поток:

ps = new PrintStream(c.getOutputStream());
ps.println(szSourceStr);
ps.close();

Переданные таким образом данные попадут в стандартный поток ввода программы CGI, откуда она их и прочитает.

Сделав это, программа CGI запишет в стандартный выходной поток строку ответа, которую необходимо прочитать в методе run нашего аплета. Для этого мы открываем входной поток, создаем на его основе форматированный входной поток данных, читаем одну строку текста и закрываем входной поток:

is = new DataInputStream(c.getInputStream());
String szReceived;
szReceived = is.readLine();
is.close();

Сразу после этого программа CGI завершит свою работу и будет готова к обработке новых запросов на добавление записей. Что же касается метода run, то он добавит полученную от расширения сервера текстовую строку в многострочное окно редактирования, как это показано ниже, а затем инициирует перерисовку окна аплета:

txta.appendText(szReceived + "\r\n");
repaint();

Заметим, что использованный нами способ передачи данных подходит только для латинских символов. Если вам нужно передавать символы кириллицы, следует преобразовывать их из кодировки UNICODE, например, в гексадецимальную кодировку, а в программе CGI выполнять обратное преобразование. Аналогичную методику можно применять и для передачи произвольных двоичных данных.

Исходный текст программы CGI store.exe

Исходный текст программы CGI store.exe очень прост и показан в листинге 7.

Листинг 7. Файл store.c

#include <windows.h>
#include <tchar.h>
#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(int argc, char *argv[])
{
  int   nInDatasize;
  char  * szMethod;
  char  szBuf[2000];
  FILE *fDatabase;
  CRITICAL_SECTION csAddRecord;
  szMethod = getenv("REQUEST_METHOD");
  if(!strcmp(szMethod, "POST"));
  {
    nInDatasize = atoi(
      getenv("CONTENT_LENGTH"));
    fread(szBuf, nInDatasize, 1, stdin);
    szBuf[nInDatasize] = '\0';
    InitializeCriticalSection(&csAddRecord);
    EnterCriticalSection(&csAddRecord);
    fDatabase =
      fopen("c:\\EMAIL.DAT", "a+");
    if(fDatabase != NULL)
    {
      fputs(szBuf, fDatabase);
      fclose(fDatabase);
    }
    LeaveCriticalSection(&csAddRecord);
    DeleteCriticalSection(&csAddRecord);
    printf(
      "Content-type: text/plain\r\n\r\n");
    printf("Stored information: %s", szBuf);
  }
}

Этот текст подготовлен для работы в среде Windows 95 или Windows NT, так как для синхронизации доступа к файлу мы использовали специфические для этих операционных систем функции работы с критическими секциями.

Свою работу программа CGI начинает с анализа переменной среды REQUEST_METHOD. Убедившись, что при запуске программы ей передали данные методом POST, программа определяет размер этих данных исходя из содержимого переменной среды CONTENT_LENGTH.

Далее программа считывает соответствующее количество байт данных из стандартного потока ввода, записывает их в файл. Затем, после добавления заголовка "Stored information:", программа CGI записывает полученную строку в стандартный выходной поток, передавая ее таким образом аплету Form.

Так как при реальной работе в сети Internet вашу программу CGI могут одновременно запустить несколько пользователей, для синхронизации обновления файла базы данных мы применили критическую секцию. В результате с файлом может работать в любой момент времени только одна копия программы CGI.

Еще одно замечание касается пути к файлу, который в нашем случае создается в корневом каталоге диска C:. При установке программы CGI на сервер вам необходимо обеспечить доступ на запись к каталогу, в котором располагается файл, для удаленных пользователей. О том, как это сделать, вы можете узнать из документации на ваш сервер Web.


Растровые изображения
Растровые изображения
Загрузка и рисование
Класс Image
Ожидание загрузки
Видео
Аплет CDRotation

Растровые изображения и анимация

Назад Вперед

Одно из наиболее распространенный применений аплетов связано с рисованием простых или анимированных растровых изображений. На серверах Web изображения обычно хранятся в форматах GIF или JPEG. Оба эти формата обеспечивают сжатие изображения, что весьма актуально из-за невысокой скорости передачи данных в сети Internet.

Рисование растровых изображений в приложениях для операционной системы Windows, составленных на языке программирования С - непростая задача. В классическом программном интерфейсе этой операционной системы отсутствуют функции, с помощью которых можно было бы непосредственно рисовать содержимое файлов с растровыми изображениями. Программист вынужден работать с заголовками таких файлов, выделять таблицу цветов и биты изображений, создавать и реализовывать палитру, заниматься восстановлением сжатых данных и так далее.

Разработчик приложений Java находится в намного лучшем положении, так как библиотеки классов Java содержат простые в использовании и мощные средства, предназначенные для работы с растровыми изображениями. В этой статье мы научим вас рисовать в окне аплета содержимое файлов GIF и JPEG, выполняя при необходимости масштабирование, а также создавать на базе таких файлов анимационные изображения, показывая по очереди отдельные кадры небольшого видеофильма.


Загрузка и рисование
Растровые изображения
Загрузка и рисование
Класс Image
Ожидание загрузки
Видео
Аплет CDRotation

Загрузка и рисование растрового изображения

Назад Вперед

Загрузка растрового изображения из файла выполняется очень просто - с помощью метода getImage, определенного в классе Applet:

public Image getImage(URL url);
public Image getImage(URL url, String name);

Первый вариант метода предполагает использование только одного параметра - адреса URL файла графического изображения. Второй позволяет дополнительно указать относительное расположение файла изображения относительно адреса URL, например:

Image img;
img = getImage(
"http://www.glasnet.ru/~frolov/pic","cd.gif");

Если аплет желает загрузить изображение, расположенное в том же каталоге, что и он сам, это можно сделать следующим образом:

img = getImage(getCodeBase(), "cd.gif");

Метод getCodeBase, определенный в классе Applet, возвращает адрес URL аплета. Вместо него можно использовать метод getDocumentBase, который также определен в классе Applet и возвращает адрес URL документа HTML, содержащего аплет:

img = getImage(getDocumentBase(), "cd.gif");

В любом случае метод getImage создает объект класса Image.

Заметим, что на самом деле метод getImage вовсе не загружает изображение через сеть, как это можно было бы подумать. Он только создает объект класса Image. Реальная загрузка файла растрового изображения будет выполняться методом рисования drawImage, который определен в классе Graphics:

public abstract boolean
  drawImage(Image img, int x, int y,
            ImageObserver observer);
public abstract boolean
  drawImage(Image img, int x, int y,
    Color bgcolor, ImageObserver observer);
public abstract boolean
  drawImage(Image img, int x, int y,
    int width, int height,
    ImageObserver observer);
public abstract boolean
  drawImage(Image img, int x, int y,
    int width, int height,
    Color bgcolor, ImageObserver observer);

Как видите, существует четыре варианта этого метода.

В качестве первого параметра любому варианту метода передается ссылка на объект класса Image, полученный ранее с помощью метода getImage.

Параметры x и y задают координаты верхнего левого угла прямоугольной области, внутри которой будет нарисовано изображение. Эти параметры также задаются для любого варианта метода drawImage.

Параметр bgcolor задает цвет фона, на котором будет нарисовано изображение. Как вы, вероятно, знаете, изображения GIF могут быть прозрачными. В этом случае цвет фона может иметь большое значение.

Если для рисования выбраны варианты метода drawImage с параметрами width и height, изображение будет нарисовано с масштабированием. При этом указанные параметры будут определять, соответственно, ширину и высоту изображения.

Параметр observer представляет собой ссылку на объект класса ImageObserver, который получит извещение при загрузке изображения. Обычно в качестве такого объекта используется сам аплет, поэтому данный параметр указывается как this.

Вот два примера использования метода drawImage:

g.drawImage(FloppyDiskImg, 25, 3, this);
g.drawImage(FloppyDiskImg,
  25, 42, 200, 200, this);

В первой строке изображение FloppyDiskImg рисуется в точке с координатами (25, 3) без масштабирования, во второй - в точке с координатами (25, 42), причем высота и ширина нарисованного изображения будет равна 200 пикселам.

Метод drawImage запускает процесс загрузки и рисования изображения, а затем, не дожидаясь его завершения, возвращает управление. Так как загрузка файла изображения по сети может отнять немало времени, она выполняется асинхронно в отдельной задаче.


Класс Image
Растровые изображения
Загрузка и рисование
Класс Image
Ожидание загрузки
Видео
Аплет CDRotation

Класс Image

Назад Вперед

Процесс рисования растрового изображения в окне аплета предельно прост - вам достаточно загрузить изображение методом getImage и затем нарисовать его методом drawImage.

Но не забывайте, что метод getImage в действительности только создает объект класса Image, но не загружает его. Давайте посмотрим на класс Image.

В этом классе имеется единственный конструктор без параметров:

public Image();

Вы, однако, скорее всего будете создавать объекты класса Image при помощи метода getImage.

Методы getHeight и getWidth, определенные в классе Image, позволяют определить, соответственно, высоту и ширину изображения:

public abstract int getHeight(
  ImageObserver observer);
public abstract int getWidth(
  ImageObserver observer);

Так как при вызове этих методов изображение еще может быть не загружено, в качестве параметров методам передается ссылка на объект ImageObserver. Этот объект получит извещение, когда будет доступна высота или ширина изображения.

Метод getGraphics позволяет получить так называемый внеэкранный контекст отображения для рисования изображения не в окне аплета, а в оперативной памяти:

public abstract Graphics getGraphics();

Эта техника используется для того, чтобы вначале подготовить изображение в памяти, а затем за один прием отобразить его на экране.

Еще один метод класса Image, который мы рассмотрим, называется flush:

public abstract void flush();

Он освобождает ресурсы, занятые изображением.


Ожидание загрузки
Растровые изображения
Загрузка и рисование
Класс Image
Ожидание загрузки
Видео
Аплет CDRotation

Ожидание загрузки изображений

Назад Вперед

Как мы уже говорили в наших предыдущих статьях, загрузка изображений из сети Internet - длительный процесс, который в среднем идет со скоростью 1 Кбайт в секунду. Поэтому изображения загружаются навигатором в отдельной задаче. При этом метод getImage только создает объект класса Image, а метод drawImage инициирует загрузку изображения и рисует его. Причем если файл изображения имеет большую длину, он будет появляться в окне аплета постепенно по мере загрузки.

Однако в некоторых случаях было бы удобно вначале загрузить изображение полностью, а лишь затем выполнять рисование, чтобы изображение появилось на экране сразу. Кроме того, аплет может рисовать сразу несколько изображений в разных местах своего окна или показывать их по очереди в одном и том же месте для достижения эффекта анимации.

Есть ли способ определить, когда изображение будет загружено полностью?

Есть, и причем целых два. Один из них связан с использованием класса MediaTracker, специально предназначенного для этой цели и достаточно удобного в использовании, другой основан на переопределении одного из методов интерфейса ImageObserver.

Применение класса MediaTracker

Для того чтобы выполнить ожидание загрузки нескольких изображений, проще воспользоваться классом MediaTracker, а не интерфейсом ImageObserver.

Как это сделать?

Обычно метод init аплета создает объект класса MediaTracker с помощью конструктора и добавляет в него все изображения, загрузки которых необходимо дождаться.

Создание объекта класса MediaTracker

Объект класса MediaTracker создается следующим образом:

MediaTracker mt;
mt = new MediaTracker(this);

Конструктору класса MediaTracker передается ссылка на компонент, для которого необходимо отслеживать загрузку изображений. В данном случае это наш аплет, поэтому мы передаем конструктору значение this.

Добавление изображений в объект класса MediaTracker

Далее метод init должен создать все необходимые объекты класса Image и добавить их в объект MediaTracker методом addImage. Ниже мы показали фрагмент кода, в котором выполняется добавление трех изображений:

Image img1;
Image img2;
Image img3;
img1 = getImage(getCodeBase(), "pic1.gif");
img2 = getImage(getCodeBase(), "pic2.gif");
img3 = getImage(getCodeBase(), "pic3.gif");
mt.addImage(img1 , 0);
mt.addImage(img2 , 0);
mt.addImage(img3 , 0);

В качестве первого параметра методу addImage передается ссылка на изображение, загрузку которого необходимо отслеживать, а в качестве второго - идентификатор, который можно будет использовать в процессе отслеживания. Если все, что вам нужно, это дождаться окончания загрузки изображений, то для второго параметра вы можете указать нулевое значение.

Ожидание загрузки добавленных изображений

Для того чтобы убедиться, что все изображения загружены, вы можете воспользоваться методом waitForAll. Этот метод инициирует загрузку изображений, а также задержит выполнение вызвавшего потока до момента полной загрузки всех изображений, добавленных в объект класса MediaTracker:

try
{
  mt.waitForAll();
}
catch (InterruptedException ex)
{
}

Обратите внимание, что метод waitForAll может создавать исключение InterruptedException. Это исключение возникает, если по какой-либо причине процесс ожидания прерывается.

Чаще всего рисование выполняется в отдельном потоке, поэтому метод waitForAll должен вызываться в начале соответствующего метода run. Ниже мы привели исходные тексты приложения ImageDrawWait, в котором такое ожидание выполняется в методе paint, что приводит, однако, к блокировке работы аплета до момента загрузки всех изображений. В данном случае это не критично, так как кроме рисования изображений наш аплет ничего не делает, однако более предпочтительным является выполнение длительных процессов в отдельном потоке.

Другие методы класса MediaTracker

Какие другие полезные методы, кроме методов addImage и waitForAll есть в классе MediaTracker?

public boolean waitForAll(long ms);

Метод waitForAll с параметром ms позволяет выполнять ожидание в течение заданного времени. Время ожидания задается в миллисекундах. При этом если за указанное время все изображения были успешно загружены, метод waitForAll возвращает значение true, если нет - false.

Вариант метода checkAll с параметром load позволяет проверить, завершилась ли загрузка отслеживаемых изображений:

public boolean checkAll(boolean load);

Если значение параметра load равно true, метод инициирует загрузку изображений.

Если при добавлении изображений методом addImage вы использовали второй параметр этого метода для присваивания разным группам изображений различные идентификаторы, то с помощью метода checkID можно дождаться завершения загрузки отдельной группы изображений:

public boolean checkID(int id);

Есть также вариант этого метода, позволяющий проверить загрузку группы изображений с заданным идентификатором:

public boolean checkID(int id, boolean load);

Метод waitForID с параметрами id и ms позволяет выполнять ожидание загрузки группы изображений с заданным идентификатором в течении указанного периода времени:

public boolean waitForID(int id, long ms);

Класс MediaTracker предоставляет также возможность прослеживать сам процесс загрузки всех добавленных в него изображений или отдельных групп изображений с помощью методов statusAll и statusID:

public int statusAll(boolean load);
public int statusID(int id, boolean load);

В зависимости от значения параметра load эти методы могут инициировать загрузку изображений. Если параметр равен true, загрузка изображений инициируется, если false - выполняется только проверка текущего состояния загрузки.

Методы statusAll и statusID возвращают значение, составленное из отдельных битов состояния при помощи логической операции ИЛИ. Ниже мы перечислили эти биты состояния и привели их краткое описание.

Биты состояния | Описание
MediaTracker.LOADING | Один или несколько отслеживаемых файлов продолжают загружаться
MediaTracker.ABORTED | Загрузка одного или нескольких файлов была прервана
MediatTracker.ERRORED | При загрузке одного или нескольких файлов произошла ошибка
MediaTracker.COMPLETE | Загрузка всех отслеживаемых файлов произошла полностью и успешно

Еще четыре метода, определенных в классе MediaTracker, связаны с обработкой ошибок:

public boolean isErrorAny();
public boolean isErrorID(int id);
public Object[] getErrorsAny();
public Object[] getErrorsID(int id);

Методы isErrorAny и isErrorID позволяют проверить, возникла ли ошибка при загрузке, соответственно, любого из отслеживаемых изображений или изображений из заданной группы. Если ошибка произошла, возвращается значение true, если нет - значение false.

Методы getErrorsAny и getErrorsID возвращают массив объектов, при ожидании загрузки которых произошла ошибка. Первый из этих методов возвращает массив для всех отслеживаемых объектов, второй - только объектов из заданной группы.

Применение интерфейса ImageObserver

Второй способ ожидания завершения процесса загрузки изображений связан с интерфейсом ImageObserver:

Биты флагов для параметра infoflags метода imageUpdate

public final static int ABORT;
public final static int ALLBITS;
public final static int ERROR;
public final static int FRAMEBITS;
public final static int HEIGHT;
public final static int PROPERTIES;
public final static int SOMEBITS;
public final static int WIDTH;

Метод imageUpdate

public abstract boolean
  imageUpdate(Image img, int infoflags,
  int x, int y, int width, int height);

Как видите, в интерфейсе ImageObserver определен единственный метод imageUpdate и набор битовых флагов для этого метода.

Класс Component, от которого происходит класс Applet, реализует интерфейс ImageObserver:

public abstract class java.awt.Component
  extends java.lang.Object
  implements java.awt.image.ImageObserver
{
  . . .
}

Этот интерфейс используется для отслеживания процесса загрузки и перерисовки изображений и других компонент, расположенных внутри компонента. В частности, он используется для отслеживания загрузки и рисования растровых изображений в окне аплета, чем мы и воспользуемся.

В процессе загрузки вызывается метод imageUpdate, поэтому чтобы отслеживать загрузку изображений, наш аплет должен переопределить этот метод.

Процедура ожидания загрузки изображений достаточно проста.

Прежде всего, аплет должен передать в последнем параметре методу drawImage ссылку на интерфейс ImageObserver, который будет применяться для отслеживания процесса загрузки:

g.drawImage(Img, x, y,
  width, height, this);

Здесь в качестве ссылки на интерфейс ImageObserver мы передали значение this. При этом будет применен интерфейс нашего аплета. Соответственно, нам нужно определить в классе аплета метод imageUpdate, который будет вызываться в процессе загрузки изображений.

Ниже мы привели возможный вариант реализации этого метода:

public boolean imageUpdate(
  Image img, int flags,
  int x, int y, int w, int h)
{
  // Проверяем, все ли
  // биты изображения загружены
  fAllLoaded = ((flags & ALLBITS) != 0);

  // Если все, перерисовываем окно
  if(fAllLoaded)
    repaint();

  // Если все биты загружены,
  // дальнейшие вызовы
  // метода imageUpdate не нужны
  return !fAllLoaded;
}

Через первый параметр img методу imageUpdate передается ссылка на изображение, загрузка которого отслеживается.

Параметр flags отражает состояние процесса загрузки.

Через остальные параметры x, y, w и h передаются, соответственно, координаты и размеры изображения.

Основное, что должен делать метод imageUpdate для отслеживания процесса загрузки - это проверять флаги flags, дожидаясь установки нужных флагов.

Флаги определены следующим образом:

public final static int WIDTH;
public final static int HEIGHT = 2;
public final static int PROPERTIES = 4;
public final static int SOMEBITS = 8;
public final static int FRAMEBITS = 16;
public final static int ALLBITS = 32;
public final static int ERROR = 64;
public final static int ABORT = 128;

Ниже мы привели краткое описание перечисленных флагов.

Флаг | Описание
WIDTH | Изображение загружено настолько, что стала доступна его ширина. Значение ширины изображения можно получить из параметра w метода imageUpdate
HEIGHT | Аналогично предыдущему, но для высоты изображения. Высоту изображения можно получить из параметра h метода imageUpdateimageUpdate
PROPERTIES | Стали доступны свойства изображения, которые можно получить методом getProperty класса Image. В нашей книге мы опустили описание этого метода
SOMEBITS | Стали доступны биты изображения для рисования в масштабе. Через параметры x, y, h и w передаются координаты и размеры прямоугольной области, которая ограничивает загруженную часть изображения
FRAMEBITS | Загружен очередной фрейм изображения, состоящего из нескольких фреймов. Параметры x, y, h и w следует игнорировать
ALLBITS | Изображение загружено полностью. Параметры x, y, h и w следует игнорировать
ERROR | При загрузке произошла ошибка
ABORT | Загрузка изображения была прервана или отменена

Анализируя состояние флагов, метод imageUpdate может следить за ходом загрузки изображений, отображая, например, процент завершения процесса загрузки или выполняя какие-либо другие действия.

Если вам нужно только дождаться завершения процесса загрузки, достаточно использовать флаг ALLBITS. Для проверки ошибок воспользуйтесь флагами ERROR и ABORT.


Видео
Растровые изображения
Загрузка и рисование
Класс Image
Ожидание загрузки
Видео
Аплет CDRotation

Видео в окне аплета

Назад Вперед

Наиболее динамичные страницы сервера Web содержат анимационные изображения в виде небольших видеофильмов. Вы можете подготовить видеофильм как файл AVI или как многосекционный файл GIF.

Файл AVI представляет собой многопоточный файл, содержащий видео и звук. Файлы AVI можно создавать при помощи специального видеоадаптера, который способен оцифровывать сигнал с видеокамеры или видеомагнитофона, а также из отдельных изображений, составляющих кадры видеофильма.

Заметим, однако, что озвученный видеофильм в формате AVI продолжительностью в 1 минуту занимает мегабайты дискового пространства. При существующих на сегодняшний день скоростях передачи данных через Internet не имеет никакого смысла размещать на страницах сервера Web файлы такого размера.

Многосекционные файлы GIF не содержат звуковой информации и состоят обычно из одного-двух десятков кадров. Для каждого такого кадра вы можете задавать время отображения и координаты, где этот кадр будет отображаться. Можно также добиться зацикленного отображения видеофильма, созданного как многосекционный файл GIF.

Аплеты Java предоставляют вам еще одну возможность отображения небольших видеофильмов на страницах сервера Web.

Для реализации этой возможности вы должны подготовить и разместить в одном из каталогов сервера Web файлы отдельных кадров видеофильма в формате GIF или JPEG.

Аплет Java должен загрузить эти изображения, дождавшись окончания процесса загрузки, что можно сделать либо при помощи рассмотренного в этой главе класса MediaTracker либо при помощи интерфейса ImageObserver.

Как только все изображения будут полностью загружены, аплет может начинать их поочередное отображение в цикле. Этот цикл должен выполняться в отдельной задаче.

Так как аплет полностью контролирует отображение кадров фильма, он может реализовывать эффекты, недостижимые при использовании файлов AVI или многосекционных файлов GIF. Например, аплет может накладывать или смешивать кадры различных фильмов, рисовать поверх кадров произвольные изображения или делать надписи, масштабировать отдельные фрагменты кадров или весь кадр и так далее. Здесь все ограничивается главным образом вашей фантазией.

Так как мы уже научились выполнять все необходимые для показа видеофильма операции, перейдем сразу к исходным текстам приложения CDRotation.


Аплет CDRotation
Растровые изображения
Загрузка и рисование
Класс Image
Ожидание загрузки
Видео
Аплет CDRotation

Аплет CDRotation

Назад Вперед

В этом разделе мы расскажем об аплете CDRotation, в окне которого вращается компакт-диск.

В левом верхнем углу каждого кадра отображается его порядковый номер (рис. 1). Этот номер не нарисован в файлах кадров, а надписывается приложением после рисования очередного кадра. Такое невозможно, если располагать в документе HTML файл AVI или многосекционный файл GIF.

pic01.gif (3268 bytes)

Рис. 1. Изображение вращающегося компакт-диска в окне аплета CDRotation

Исходные тексты приложения

Главный файл исходных текстов приложения CDRotation представлен в листинге 1.

Листинг 1. Файл CDRotation.java

import java.applet.*;
import java.awt.*;
public class CDRotation extends Applet
  implements Runnable
{
  Thread m_CDRotation = null;
  private Graphics m_Graphics;
  private Image m_Images[];
  private int m_nCurrImage;
  private int m_nImgWidth  = 0;
  private int m_nImgHeight = 0;
  private boolean m_fAllLoaded = false;
  private final int NUM_IMAGES = 11;
  public String getAppletInfo()
  {
    return "Name: CDRotation";
  }
  private void displayImage(Graphics g)
  {
    if (!m_fAllLoaded)
      return;
    g.drawImage(m_Images[m_nCurrImage],
       (size().width - m_nImgWidth)   / 2,
       (size().height - m_nImgHeight) / 2,
        null);
    g.drawString(
      (new Integer(m_nCurrImage)).toString(),
      (size().width - m_nImgWidth)  /2,
     ((size().height - m_nImgHeight)/2)+
     10);
  }
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension = size();
    g.setColor(Color.white);
    g.fillRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    if (m_fAllLoaded)
    {
      displayImage(g);
    }
    else
      g.drawString("Please, wait...",
        10, dimAppWndDimension.height / 2);
  }
  public void start()
  {
    if (m_CDRotation == null)
    {
      m_CDRotation = new Thread(this);
      m_CDRotation.start();
    }
  }
  public void stop()
  {
    if (m_CDRotation != null)
    {
      m_CDRotation.stop();
      m_CDRotation = null;
    }
  }
  public void run()
  {
    m_nCurrImage = 0;
    if (!m_fAllLoaded)
    {
      repaint();
      m_Graphics = getGraphics();
      m_Images   = new Image[NUM_IMAGES];
      MediaTracker tracker =
         new MediaTracker(this);
      String strImage;
      for (int i = 0; i < NUM_IMAGES; i++)
      {
        strImage = "images/cdimg0" +
          ((i < 10) ? "0" : "") + i + ".gif";
        m_Images[i] = getImage(
          getDocumentBase(), strImage);
        tracker.addImage(m_Images[i], 0);
      }
      try
      {
    tracker.waitForAll();
    m_fAllLoaded = !tracker.isErrorAny();
      }
      catch (InterruptedException e)
      {
      }
      if (!m_fAllLoaded)
      {
        stop();
        m_Graphics.drawString(
          "Load error", 10,
           size().height / 2);
        return;
      }
      m_nImgWidth  =
        m_Images[0].getWidth(this);
      m_nImgHeight =
         m_Images[0].getHeight(this);
    }
    repaint();
    while (true)
    {
      try
      {
        displayImage(m_Graphics);
    m_nCurrImage++;
    if(m_nCurrImage == NUM_IMAGES)
    m_nCurrImage = 0;
        Thread.sleep(30);
      }
      catch (InterruptedException e)
      {
    stop();
      }
    }
  }
}

Листинг 2 содержит исходный текст документа HTML, созданного для аплета CDRotation.

Листинг 2. Файл CDRotation.tmp.html

<applet name="CDRotation"
  code="CDRotation"
  codebase=
"file:/e:/sun/articles/vol13/src/CDRotation"
  width="500"
  height="600"
  align="Top"
  alt="If you had a java-enabled browser,
 you would see an applet here.">
</applet>

Описание исходных текстов

Рассмотрим наиболее важные методы нашего аплета.

Метод start

В задачу метода start, который получает управление при отображении окна аплета, входит создание и запуск потока, отображающего кадры видеофильма с изображением вращающегося компакт-диска:

if (m_CDRotation == null)
{
  m_CDRotation = new Thread(this);
  m_CDRotation.start();
}

Поток создается как объект класса Thread, причем конструктору передается ссылка на главный класс аплета. Поэтому при запуске потока управление получит метод run, определенный в классе аплета.

Метод stop

Метод stop останавливает работу потока, когда окно аплета исчезает с экрана:

if(m_CDRotation != null)
{
  m_CDRotation.stop();
  m_CDRotation = null;
}

Для остановки вызывается метод stop.

Метод paint

Сразу после получения управления, метод paint закрашивает окно аплета белым цветом и рисует вокруг него черную рамку.

Затем метод проверяет содержимое флага m_fAllLoaded. Этот флаг установлен в значение true, когда все кадры видеофильма загружены и сброшен в значение false, когда загрузка кадров еще не завершена. Последняя ситуация возникает всегда при первом вызове метода paint.

Если все изображения загружены, метод paint вызывает метод displayImage, определенный в нашем приложении:

if(m_fAllLoaded)
{
  displayImage(g);
}

Этот метод, о котором мы еще расскажем подробнее, отображает в окне аплета текущий кадр видеофильма.

Если же кадры видеофильма еще не загружены, в окне аплета отображается соответствующее сообщение:

else
  g.drawString("Please, wait...",
    10, dimAppWndDimension.height / 2);

Метод run

Метод run работает в рамках отдельного потока. Он занимается последовательным рисованием кадров нашего видеофильма.

Прежде всего метод run записывает нулевое значение в поле m_nCurrImage, хранящее номер текущего отображаемого кадра:

m_nCurrImage = 0;

Далее выполняется проверка, загружены ли все кадры видеофильма, для чего анализируется содержимое флага m_fAllLoaded.

Если изображения не загружены (а в самом начале так оно и есть) метод run перерисовывает окно аплета и получает контекст отображения для этого окна. Затем создается массив объектов Image для хранения кадров видеофильма:

m_Images   = new Image[NUM_IMAGES];

Метод run создает также объект класса MediaTracker для ожидания загрузки всех кадров видеофильма:

MediaTracker tracker =
  new MediaTracker(this);

Далее метод run в цикле загружает изображения и добавляет их в объект класса MediaTracker для того чтобы можно было дождаться загрузки всех кадров:

for (int i = 0; i < NUM_IMAGES; i++)
{
  strImage = "images/cdimg0" +
   ((i < 10) ? "0" : "") + i + ".gif";
  m_Images[i] = getImage(
    getDocumentBase(), strImage);
  tracker.addImage(m_Images[i], 0);
}

Здесь предполагается, что файлы изображений находятся в каталоге images, который, в свою очередь, размещен там же, где и двоичный файл аплета.

Имена файлов, составляющих отдельные кадры, начинаются с префикса cdimg0, вслед за которым идет номер кадра (00, 01, 02, и так далее), и расширение имени .gif.

Ожидание загрузки кадров выполняется с помощью метода waitForAll, о котором мы вам уже рассказывали:

try
{
  tracker.waitForAll();
  m_fAllLoaded = !tracker.isErrorAny();
}
catch (InterruptedException e)
{
}

После окончания ожидания флаг завершения загрузки устанавливается только в том случае, если метод isErrorAny вернул значение false, то есть если не было никаких ошибок.

Если же произошла ошибка, в окне аплета отображается соответствующее сообщение, после чего работа метода run (и, следовательно, работа созданного для него потока) заканчивается:

if(!m_fAllLoaded)
{
  stop();
  m_Graphics.drawString(
    "Load error",
    10, size().height / 2);
  return;
}

В случае удачной загрузки всех кадров метод run получает ширину и высоту первого кадра видеофильма и сохраняет эти значения в переменных m_nImgWidth и m_nImgHeight:

m_nImgWidth  =
  m_Images[0].getWidth(this);
m_nImgHeight =
  m_Images[0].getHeight(this);

Далее окно аплета перерисовывается:

repaint();

При этом метод paint отображает в окне аплета первый кадр видеофильма.

На следующем этапе работы метода run запускается цикл отображения кадров фильма:

while (true)
{
  try
  {
    displayImage(m_Graphics);
    m_nCurrImage++;
    if(m_nCurrImage == NUM_IMAGES)
      m_nCurrImage = 0;
    Thread.sleep(30);
  }
  catch (InterruptedException e)
  {
    stop();
  }
}

В этом бесконечном цикле вызывается метод displayImage, рисующий текущий кадр видеофильма, после чего номер текущего кадра увеличивается на единицу. Если показаны все кадры, номер текущего кадра становится равным нулю, а затем процесс продолжается.

Между отображением кадров выполняется задержка величиной 30 миллисекунд.

Метод displayImage

Метод displayImage вызывается из двух мест - из метода paint при перерисовке окна аплета и из метода run (периодически).

Если кадры видеофильма не загружены, содержимое флага m_fAllLoaded равно false и метод displayImage просто возвращает управление, ничего не делая:

if(!m_fAllLoaded)
  return;

Если же загрузка изображений завершена, этот метод рисует в центре окна текущий кадр видеофильма, вызывая для этого знакомый вам метод drawImage:

g.drawImage(m_Images[m_nCurrImage],
  (size().width - m_nImgWidth)   / 2,
  (size().height - m_nImgHeight) / 2,
   null);

После того как кадр нарисован, мы надписываем на нем его порядковый номер, вызывая для этого метод drawString:

g.drawString((new Integer(
  m_nCurrImage)).toString(),
  (size().width - m_nImgWidth)   / 2,
  ((size().height - m_nImgHeight) / 2) + 10);


Звук в аплетах Java
Звук в аплетах Java
Загрузка и проигрывание звуковых файлов
Аплет PlayClip

Звук в аплетах Java

Назад Вперед

Нельзя сказать, что звуковые возможности аплетов Java чрезмерно велики. Скорее наоборот, они минимальны. Тем не менее, аплеты могут проигрывать звуковые клипы, записанные в файлах формата AU, который пришел из мира компьютеров фирмы Sun.

Сказанное, однако, не означает, что если у вас нет рабочей станции Sun, то вы не сможете озвучить свои аплеты. Во-первых, в сети Internet можно найти много готовых звуковых файлов AU, а во-вторых, там же есть программы для преобразования форматов звуковых файлов. Одну из таких условно-бесплатных программ, которая называется GoldWave, вы можете загрузить с сервера ftp.winsite.com.


Загрузка и проигрывание звуковых файлов
Звук в аплетах Java
Загрузка и проигрывание звуковых файлов
Аплет PlayClip

Загрузка и проигрывание звуковых файлов

Назад Вперед

Работа со звуковыми файлами во многом напоминает работу с растровыми графическими файлами. Вначале вы должны получить ссылку на интерфейс AudioClip, а затем, пользуясь его методами, вы сможете выполнять проигрывание содержимого этого файла.

Для получения интерфейса AudioClip вы должны воспользоваться одним из двух вариантов метода getAudioClip, определенных в классе Applet:

public AudioClip
  getAudioClip(URL url):
public AudioClip
  getAudioClip(URL url, String name);

Первый вариант метода предполагает указание адреса URL звукового файла через единственный параметр, второй допускает раздельное указание адреса URL каталога, содержащего файл, и имени файла.

В документации на метод getAudioClip сказано, что этот метод фактически не выполняет загрузку звуковых данных, а только возвращает ссылку на интерфейс AudioClip и немедленно возвращает управление. Загрузка звуковых данных выполняется методами, предназначенными для проигрывания файла.

Однако в книге "The Java Tutorial. Object-Oriented Programming for the Internet", подготовленной специалистами группы JavaSoft, утверждается, что текущие реализации Java работают по другому: метод getAudioClip возвращает управление только после завершения загрузки звукового файла. Очевидно, вам не стоит полагаться на то, что так будет всегда. В тех случаях, когда нежелательно блокирование работы аплета на время загрузки звукового файла, загрузку и проигрывание следует выполнять в отдельном потоке.

Интерфейс AudioClip определен следующим образом:

public interface java.applet.AudioClip
{
  public abstract void play();
  public abstract void loop();
  public abstract void stop();
}

Метод play запускает однократное проигрывание звукового файла, которое выполняется от начала файла и до его конца.

Метод loop запускает проигрывание звукового файла в цикле, которое будет продолжаться до тех пор, пока вы не остановите его, вызвав метод stop.

Метод stop, как нетрудно догадаться из его названия, останавливает проигрывание звукового файла, как однократное, так и выполняемое в цикле.


Аплет PlayClip
Звук в аплетах Java
Загрузка и проигрывание звуковых файлов
Аплет PlayClip

Аплет PlayClip

Назад

Аплет PlayClip демонстрирует использование интерфейса AudioClip. В его окне (рис. 1) имеются три кнопки с названиями Play, Loop и Stop.

pic01.gif (1685 bytes)

Рис. 1. Окно аплета PlayClip

Сразу после запуска аплета кнопка Stop находится в заблокированном состоянии. Если нажать кнопку Play или Loop, начнется, соответственно, однократное проигрывание или проигрывание в цикле файла с именем kaas.au, распложенного в том же каталоге, что и двоичный файл аплета PlayClip.

Когда начинается проигрывание звукового файла, кнопка Stop разблокируется, что позволяет остановить проигрывание.

Исходные тексты приложения

Основной файл исходных текстов приложения приведен в листинге 1.

Листинг 1. Файл PlayClip.java

import java.applet.*;
import java.awt.*;
public class PlayClip extends Applet
{
  private String m_ClipName = "kaas.au";
  private final String
    PARAM_ClipName = "ClipName";
  AudioClip auClip;
  Button btPlay;
  Button btLoop;
  Button btStop;
  boolean fLoopPlay = false;
  public String getAppletInfo()
  {
    return "Name: PlayClip";
  }
  public String[][] getParameterInfo()
  {
    String[][] info =
    {
      {
    PARAM_ClipName,
    "String",
    "Audioclip filename"
      },
    };
    return info;
  }
  public void init()
  {
    String param;
    param = getParameter(PARAM_ClipName);
    if (param != null)
      m_ClipName = param;
    btPlay = new Button("Play");
    btLoop = new Button("Loop");
    btStop = new Button("Stop");
    btStop.disable();
    add(btPlay);
    add(btLoop);
    add(btStop);
    auClip = this.getAudioClip(getCodeBase(),
      m_ClipName);
  }
  public boolean action(Event evt,
    Object obj)
  {
    Button btn;
    if(evt.target instanceof Button)
    {
      btn = (Button)evt.target;
      if(evt.target.equals(btPlay))
      {
        auClip.play();
        btStop.enable();
      }
      else if(evt.target.equals(btLoop))
      {
        auClip.loop();
        fLoopPlay = true;
        btStop.enable();
      }
      else if(evt.target.equals(btStop))
      {
        auClip.stop();
        fLoopPlay = false;
        btStop.disable();
      }
      else
      {
        return false;
      }
      return true;
    }
    return false;
  }
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension = size();
    g.setColor(Color.yellow);
    g.fillRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
  }
  public void start()
  {
    if(fLoopPlay)
      auClip.loop();
  }
  public void stop()
  {
    if(fLoopPlay)
      auClip.stop();
  }
}

В листинге 2 вы найдете исходный текст документа HTML, созданного автоматически для нашего приложения системой Java WorkShop.

Листинг 2. Файл PlayClip.tmp.html

<applet name="PlayClip"
  code="PlayClip"
  codebase=
"file:/e:/sun/articles/vol14/src/PlayClip"
 width="200"
 height="100"
 align="Top"
  alt="If you had a java-enabled browser,
 you would see an applet here.">
<param name="ClipName" value="kaas.au">
<hr>
If your browser recognized the applet tag,
 you would see an applet here.
<hr>
</applet>

Описание исходного текста

В главном классе аплета определено несколько полей и методов. Рассмотрим эти поля и наиболее важные методы.

Поля класса PlayClip

В поле m_ClipName хранится имя звукового файла, которое передается через параметр ClipName из документа HTML. По умолчанию для этого параметра используется значение kaas.au.

Строка PARAM_ClipName хранит имя указанного выше параметра.

Ссылка на интерфейс AudioClip хранится в поле auClip:

AudioClip auClip;

Следующие три поля хранят ссылки на кнопки, предназначенные для управления проигрыванием звукового файла:

Button btPlay;
Button btLoop;
Button btStop;

Поле fLoopPlay типа boolean используется для флага, которым отмечается режим проигрывания звукового файла в цикле.

Метод getParameterInfo

Метод getParameterInfo возвращает описание единственного параметра нашего аплета, через который передается имя звукового файла.

Метод init

Сразу после запуска аплета метод init получает значение параметра - имя звукового файла, и если этот параметр задан в документе HTML, записывает полученное имя в поле m_ClipName:

param = getParameter(PARAM_ClipName);
if(param != null)
  m_ClipName = param;

Далее создаются три кнопки, управляющие звучанием аплета:

btPlay = new Button("Play");
btLoop = new Button("Loop");
btStop = new Button("Stop");

Кнопка Stop блокируется, так как на данный момент проигрывание еще не запущено:

btStop.disable();

Для блокирования вызывается метод disable, определенный в классе Button.

Подготовленные таким образом кнопки добавляются в окно аплета:

add(btPlay);
add(btLoop);
add(btStop);

Последнее, что делает метод init перед тем как возвратить управление, это получение ссылки на интерфейс AudioClip:

auClip = this.getAudioClip(
  getCodeBase(),m_ClipName);

Адрес URL каталога, в котором расположен аплет, определяется с помощью метода getCodeBase, о котором мы говорили в предыдущей главе.

Метод action

Метод action получает управление, когда пользователь нажимает на одну из кнопок, расположенных в окне аплета. В зависимости от того, какая именно кнопка была нажата, выполняются различные действия.

Если пользователь нажал кнопку Play, вызывается метод play для запуска однократного проигрывания звукового файла:

auClip.play();
btStop.enable();

Сразу после того как проигрывание будет запущено, приложение разблокирует кнопку Stop, предоставляя пользователю возможность прервать звучание.

В том случае, когда пользователь нажал кнопку Loop, вызывается метод loop, запусчкающий проигрывание звукового файла в цикле:

auClip.loop();
fLoopPlay = true;
btStop.enable();

После запуска устанавливается флаг fLoopPlay и разблокируется кнопка Stop.

И, наконец, если пользователь нажимает кнопку Stop, выполняется остановка проигрывания методом stop:

auClip.stop();
fLoopPlay = false;
btStop.disable();

Флаг fLoopPlay сбрасывается, после чего кнопка Stop блокируется.

Метод start

Метод start получает управление при первом запуска аплета, а также когда страница документа появляется вновь после того как пользователь временно переходил к просмотру другой страницы.

Наша реализация метода start возобновляет циклическое проигрывание, если оно выполнялось, когда пользователь покинул страницу с аплетом:

if(fLoopPlay)
  auClip.loop();

Метод stop

Если пользователь запустил проигрывание звукового файла в цикле, а затем перешел к просмотру другой страницы, метод stop останавливает циклическое проигрывание:

if(fLoopPlay)
  auClip.stop();

Когда пользователь вернется к просмотру нашей страницы, метод start, описанный выше, возобновит проигрывание звукового файла.

Назад


Первое приложение
Первое приложение
Установка WorkShop
Запуск Java WorkShop
Текст HelloJava

Первое приложение Java

Назад Вперед

Как мы уже говорили, приложение Java может выполняться под управлением специального интерпретатора, работающего в рамках отдельного процесса, либо под управлением браузера. В первом случае мы имеем дело с автономным приложением Java, в втором - с аплетом.

Изучение программирования на Java мы начнем с создания простейшего автономного приложения. В следующей статье мы расскажем о том, как сделать аплет и встроить его в документ HTML.

В качестве инструментального средства для разработки автономных приложений и аплетов Java мы будем использовать интегрированную систему разработки Java WorkShop. Она доступна для операционных систем Windows 95, Windows NT, Solaris (платформы SPARC и Intel).


Установка WorkShop
Первое приложение
Установка WorkShop
Запуск Java WorkShop
Текст HelloJava

Установка Java WorkShop

Назад Вперед

Для установки Java WorkShop вы должны вставить дистрибутивный диск в устройство чтения CD-ROM. Программа установки запустится автоматически. Если этого не произошло (например, потому что автоматический запуск заблокирован), следует запустить программу установки вручную.

Если вы работаете в среде Windows 95 или Windows NT, вам нужно запустить программу setup.exe из каталога Win32. На дистрибутивном диске Java WorkShop есть также установочные каталоги для других платформ.

Процедура установки очень проста. Достаточно следовать инструкциям, которые появляются на экране. Единственное, что необходимо выбрать - это путь к каталогу, в который будут скопированы файлы Java WorkShop. При этом следует учесть, что для установки Java WorkShop в среде Windows 95 или Windows NT требуется примерно 50 Мбайт дисковой памяти.


Запуск Java WorkShop
Первое приложение
Установка WorkShop
Запуск Java WorkShop
Текст HelloJava

Запуск Java WorkShop

Назад Вперед

После завершения установки следует извлечь дистрибутивный компакт-диск и запустить Java WorkShop, воспользовавшись пиктограммой, созданной на рабочем столе операционной системы.

Когда система разработки Java WorkShop запускается впервые, она требует ввести серийный номер. Этот номер есть на вкладыше в конверте дистрибутивного компакт-диска. В том случае, если вы располагаете демонстрационной версией Java WorkShop, серийный номер можно не вводить. При этом вы сможете пользоваться Java WorkShop бесплатно в течении 30 дней.

После запуска Java WorkShop на экране появится главное окно Java WorkShop (рис.1), а также окно Java WorkShop Startup (рис. 2).

pic01sm.gif (2606 bytes) Рис. 1. Главное окно интегрированной системы разработки Java WorkShop

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

pic02sm.gif (3257 bytes) Рис. 2. Окно Java WorkShop Startup

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Если раньше вы никогда не работали с Java WorkShop, окно Java WorkShop Startup поможет вам освоиться с основными процедурами. Нажав соответствующую кнопку, вы можете создать свой первый проект, открыть пример проекта, подготовленного для вас специалистами Sun Microsystems, ознакомиться с электронным руководством или справочной системой, а также открыть любой существующий проект.

После приобретения небольшой практики можно включить переключатель Don't show me this window at startup, и окно Java WorkShop Startup перестанет появляться всякий раз, когда вы запускаете Java WorkShop.

Создание нового проекта

Как и многие другие интегрированные системы разработки программного обеспечения, система Java WorkShop использует концепцию проектов. Под проектом здесь понимается совокупность файлов и параметров, описанные в специальном файле проектов.

Всеми проектами в Java WorkShop управляет менеджер проектов. Чтобы открыть его окно, показанное на рис. 3, выберите строку Show Project Manager из меню Project главного окна Java WorkShop.

pic03.gif (4211 bytes)

Рис. 3. Окно Java WorkShop Project Manager

Все проекты хранятся в портфелях (portfolios). В процессе установки автоматически создается ваш личный портфель personal, который находится в папке My Portfolios. В этом портфеле есть проекты Checkers, CardFile, JellyBeanExample и Performance Example. При создании нового проекта мы добавим его в портфель personal, хотя в дальнейшем вы сможете создавать новые портфели.

Прежде чем выполнять какие либо операции над портфелем или проектом, нужно сделать этот портфель или проект текущим. Чтобы выбрать текущий портфель или проект, следует сделать двойной щелчок левой клавишей мыши по соответствующему названию. Строка названия будет выделена синим цветом.

Для создания проекта HelloJava выберите из меню File окна Java WorkShop Project Manager строку New, а затем в меню второго уровня строку Project. В результате будет запущен мастер создания проектов, первая диалоговая панель которого показана на рис. 4.

pic04sm.gif (2051 bytes) Рис. 4. Первая диалоговая панель мастера проектов

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

В поле Please, name this project введите название создаваемого проекта HelloJava, затем включите переключатели Standalone и No GUI. Первый из этих переключателей задает тип проекта (автономное приложение Java), второй указывает, что в проекте не используются средства автоматизированного проектирования пользовательского интерфейса.

Далее нажмите кнопку Next. Вы окажитесь в диалоговой панели Create Project, показанной на рис. 5.

pic05sm.gif (1881 bytes) Рис. 5. Диалоговая панель Create Project

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

В верхней части этой панели вы должны ввести путь к каталогу, в котором будут создаваться файлы проекта. Затем следует включить переключатель No, указывая тем самым, что каталог проектов пуст и в нем нужно создать новые файлы. Существует возможность создания проектов на базе уже имеющихся файлов, однако пока мы этого делать не будем.

Теперь все готово к созданию проекта и вы можете нажать кнопку Finish. Мастер проектов создаст все необходимые файлы и сделает новый проект текущим. Основной файл проекта окажется загруженным в главное окно приложения Java WorkShop (рис. 6). Здесь вы можете его редактировать.

pic06sm.gif (2479 bytes) Рис. 6. Основной файл созданного проекта загружен в окно приложения Java WorkShop

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Если теперь вы раскроете окно Java WorkShop Project Manager, то увидите, что в портфеле personal появился новый проект HelloJava. Раскрыв его, можно увидеть включенные в него файлы (рис. 7).

pic07.gif (5130 bytes)

Рис. 7. Файлы проекта HelloJava.

Наш проект содержит только один файл с именем HelloJava.java. Отредактируйте этот файл, добавив в него следующую строку:

System.out.println("Hello, Java!");

Новый вариант исходного текста показан на рис. 8.

pic08sm.gif (2810 bytes) Рис. 8. Измененный исходный текст приложения HelloJava

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Теперь выберите из меню Build главного окна Java WorkShop строку Build All. Через несколько мгновений исходные тексты приложения будут оттранслированы. Результат вы сможете увидеть нас странице Build блокнота, расположенного в нижней части окна Java WorkShop.

Чтобы запустить приложение, выберите из меню Project строку Run. На экране появится консоль приложения с сообщением "Hello, Java!" (рис. 9).

pic09.gif (3009 bytes)

Рис. 9. Работа приложения Hello, Java!


Текст HelloJava
Первое приложение
Установка WorkShop
Запуск Java WorkShop
Текст HelloJava

Исходный текст приложения HelloJava

Назад Вперед

Исходный текст нашего первого приложения состоит всего из нескольких строк:

public class HelloJava
{
  public static void main(String args[])
  {
    System.out.println("Hello, Java!");
  }
}

По своей простоте он не уступает известной программе "Hello, world!", с которой обычно начинают изучение языка программирования C.

В нашем приложении определен один класс типа public с именем HelloJava. Заметим, что исходный файл приложения Java может содержать только один класс public, причем имя файла должно в точности совпадать с именем такого класса. В данном случае исходный файл называется HelloJava.java. Если бы вы назвали файл helloJava.java, компилятор выдал бы сообщение об ошибке.

В классе HelloJava мастером проектов автоматически создается один статический метод с именем main.

Если класс типа public с именем, совпадающем с именем файла, содержит определение метода main, то такой метод служит точкой входа автономного приложения Java. В этом он напоминает функцию main обычной программы, составленной на языке программирования C.

В качестве параметра методу main передается ссылка на массив строк класса String. Через эти строки вы можете передавать приложению Java параметры запуска.

Как наше приложение выводит текстовую строку на консоль?

В классе System определена переменная класса PrintStream с именем out. В классе PrintStream определен метод println, при помощи которого приложение HelloJava выводит сообщение "Hello, Java!" на консоль.

Но где же объект, для которого вызывается метод println? В классе System поле PrintStream определено как статическое, поэтому методы этого класса можно вызывать, не создавая объектов класса System.


Рис. 1. Главное окно интегрированной системы разработки Java WorkShop

Для возврата сделайте щелчок мышью по рисунку

Рис. 1. Главное окно интегрированной системы разработки Java WorkShop


Рис. 2. Окно Java WorkShop Startup

Для возврата сделайте щелчок мышью по рисунку

Рис. 2. Окно Java WorkShop Startup


Рис. 4. Первая диалоговая панель мастера проектов

Для возврата сделайте щелчок мышью по рисунку

Рис. 4. Первая диалоговая панель мастера проектов


Рис.5. Диалоговая панель Create Project

Для возврата сделайте щелчок мышью по рисунку

Рис.5. Диалоговая панель Create Project


Рис.6. Основной файл созданного проекта загружен в окно приложения Java WorkShop

Для возврата сделайте щелчок мышью по рисунку

Рис.6. Основной файл созданного проекта загружен в окно приложения Java WorkShop


Рис. 8. Измененный исходный текст приложения HelloJava

Для возврата сделайте щелчок мышью по рисунку

Рис. 8. Измененный исходный текст приложения HelloJava


Первый аплет
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Первый аплет Java

Назад Вперед

В предыдущем разделе мы создавали автономное приложение Java, работающее под управлением виртуальной машины Java. Теперь мы создадим приложение другого типа - аплет.

Аплет Java тоже выполняется под управлением виртуальной машины Java, но встроенной в браузер. Когда браузер загружает в свое окно документ HTML с аплетом, байт-код аплета начинает свою работу.

Внешне аплет выглядит как окно заданного размера. Он может рисовать внутри этого окна (и только в нем) произвольные изображения и текст.

Двоичный файл с интерпретируемым байт-кодом Java располагается на сервере Web. В документе HTML с помощью оператора <APPLET> организуется ссылка на этот двоичный файл.

Когда пользователь загружает в браузер документ HTML с аплетом, файл аплета переписывается с сервера Web на рабочую станцию пользователя. После этого браузер начинает его выполнение.

Возможно, вам не понравится такая идея, как запуск чужого аплета на своем компьютере - мало ли чего этот аплет может там сделать. Однако аплеты, в отличие от обычных приложений Java, сильно ограничены в своих правах. Например, они не могут читать локальные файлы и тем более в них писать. Есть также ограничения и на передачу данных через сеть: аплет может обмениваться данными только с тем сервером Web, с которого он был загружен.


Создание проекта аплета
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Создание проекта аплета

Назад Вперед

Проект аплета создается таким же способом, что и проект автономного приложения Java, однако мастеру проектов необходимо указать другие параметры.

В первой диалоговой панели мастера проектов следует включить переключатели Applet и No GUI (рис. 1).

pic01sm.gif (2059 bytes) Рис. 1. Первая диалоговая панель мастера проектов

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Сделав это, нажмите кнопку Next. На экране появится вторая диалоговая панель мастера проектов. Здесь вы должны указать путь к каталогу, куда мастер проектов запишет файлы проекта, а также включить переключатель No (рис. 2).

pic02sm.gif (2059 bytes) Рис. 2. Вторая диалоговая панель мастера проектов

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

В результате мастер проектов создаст исходные тексты аплета, а также добавит новый проект в портфель personal (если этот портфель остался активным в последний раз, когда вы запускали Java WorkShop). Новый проект называется HelloApplet (рис. 3).

pic03.gif (5316 bytes)

Рис. 3. Новый проект появился в активном портфеле personal

Исходный текст аплета будет создан автоматически и загружен в окно редактирования системы Java WorkShop (рис. 4).

pic01sm.gif (2059 bytes) Рис. 4. Исходный текст аплета загружен в окно редактирования

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Вы можете оттранслировать полученный исходный текст и запустить аплет на выполнение. Он будет работать под управлением программы просмотра аплетов appletviewer, которая входит в состав Java WorkShop.

Пока в окне нашего аплета ничего нет (рис. 5), однако скоро мы исправим это положение.

pic05.gif (2199 bytes)

Рис. 5. Окно аплета, созданного автоматически мастером проектов


Исходный текст аплета
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Исходный текст аплета

Назад Вперед

Полный исходный текст аплета, созданный автоматически мастером проектов Java WorkShop, мы представили в листинге 1.

Листинг 1. Файл HelloApplet.java

import java.applet.Applet;
public class HelloApplet extends Applet {
  /**
  * Initializes the applet.  You never need to
  * call this directly; it is
  * called automatically by the system once the
  * applet is created.
  */
  public void init() {}

  /**
  * Called to start the applet.  You never need
  * to call this directly; it
  * is called when the applet's
  * document is visited.
  */
  public void start() {}

  /**
  * Called to stop the applet.  This is called
  * when the applet's document is
  * no longer on the screen.  It is guaranteed
  * to be called before destroy()
  * is called.  You never need to
  * call this method directly
  */
  public void stop() {}

  /**
  * Cleans up whatever resources are being held.
  * If the applet is active
  * it is stopped.
  */
  public void destroy() {}
}

Из-за обилия комментариев вы можете подумать, что исходный текст аплета, который ничего не делает, слишком сложный. Однако это вовсе не так. Вот что получится, если мы уберем все комментарии:

import java.applet.Applet;
public class HelloApplet extends Applet
{
  public void init()    {}
  public void start()   {}
  public void stop()    {}
  public void destroy() {}
}

Исходный текст нашего аплета начинается со строки, подключающей оператором import библиотеку классов java.applet.Applet.

Оператор import должен располагаться в файле исходного текста перед другими операторами (за исключением операторов комментария). В качестве параметра оператору import передается имя подключаемого класса из библиотеки классов. Если же необходимо подключить все классы данной библиотеки, вместо имени класса указывается символ "*".

Напомним, что библиотека java.applet.Applet содержит классы, необходимые для создания аплетов, то есть разновидности приложений Java, встраиваемых в документы HTML и работающих под управлением браузера Internet.

Еще одна библиотека классов, которая нам скоро понадобится, это java.awt. С ее помощью аплет может выполнять в своем окне рисование различных изображений или текста. Преимущества данного метода перед использованием для рисования традиционного программного интерфейса операционной системы заключаются в том, что он работает на любой компьютерной платформе.

Далее в исходном тексте аплета определяется класс типа public с именем HelloApplet. Напомним, что это имя должно обязательно совпадать с именем файла, содержащего исходный текст этого класса.

public class HelloApplet extends Applet
{
  . . .
}

Определенный нами класс HelloApplet с помощью ключевого слова extends наследуется от класса Applet. При этом методам класса HelloApplet становятся доступными все методы и данные класса, за исключением определенных как private. Класс Applet определен в библиотеке классов java.applet.Applet, которую мы подключили оператором import.


Методы в классе HelloApplet
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Методы в классе HelloApplet

Назад Вперед

Создавая файл HelloApplet.java, мастер проектов системы Java WorkShop определила в классе HelloApplet несколько методов, заменив таким образом некоторые методы базового класса Applet.

Метод init

Метод init определен в базовом классе Applet, от которого наследуются все аплеты. Определение его таково, что этот метод ровным счетом ничего не делает.

Когда вызывается метод init и зачем он нужен?

Метод init вызывается тогда, когда браузер загружает в свое окно документ HTML с оператором <APPLET>, ссылающимся на данный аплет. В этот момент аплет может выполнять инициализацию, или, например, создавать потоки, если он работает в многопоточном режиме.

Существует контрпара для метода init - метод destroy. О нем мы расскажем ниже.

Метод destroy

Перед удалением аплета из памяти вызывается метод destroy, который определен в базовом классе Applet как пустая заглушка. Мастер проектов добавляет в исходный текст класса переопределение метода destroy, которое вы можете при необходимости изменить.

Методу destroy обычно поручают все необходимые операции, которые следует выполнить перед удалением аплета. Например, если в методе init вы создавали какие-либо потоки, в методе destroy их нужно завершить.

Метод start

Метод start вызывается после метода init в момент, когда пользователь начинает просматривать документ HTML с встроенным в него аплетом.

Вы можете модифицировать текст этого метода, если при каждом посещении пользователем страницы с аплетом необходимо выполнять какую-либо инициализацию.

Метод stop

Дополнением к методу start служит метод stop. Он получает управление, когда пользователь покидает страницу с аплетом и загружает в окно браузера другую страницу. Заметим, что метод stop вызывается перед методом destroy.


Исходный текст документа HTML
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Исходный текст документа HTML

Назад Вперед

Кроме файла исходного текста аплета мастер проектов создал файл документа HTML HelloApplet.tmp.html, представленный в листинге 2.

Листинг 2. Файл HelloApplet.tmp.html

<applet
   name="HelloApplet"
   code="HelloApplet"
   codebase="file:/e:/sun/vol3/src/HelloApplet"
   width="500"
   height="600"
   align="Top"
   alt="If you had a java-enabled
browser, you would see an applet here.">
</applet>

С помощью оператора <applet> наш аплет встраивается в этот документ. Оператор <APPLET> используется в паре с оператором </APPLET> и имеет следующие параметры:

Параметр | Описание
ALIGN | Выравнивание окна аплета относительно окружающего его текста. Возможны следующие значения: LEFT - выравнивание влево относительно окружающего текста; CENTER - центрирование; RIGHT - выравнивание вправо относительно окружающего текста; TOP - выравнивание по верхней границе; MIDDLE - центрирование по вертикали; BOTTOM - выравнивание по нижней границе
ALT | С помощью этого параметра можно задать текст, который будет отображаться в окне аплета в том случае, если браузер не может работать с аплетами Java
CODE | Имя двоичного файла, содержащего байт-код аплета. По умолчанию путь к этому файлу указывается относительно каталога с файлом HTML, в который встроен аплет. Такое поведение может быть изменено параметром CODEBASE
CODEBASE | Базовый адрес URL аплета, то есть путь к каталогу, содержащему аплет
HEIGHT | Ширина окна аплета в пикселах
WIDTH | Высота окна аплета в пикселах
HSPACE | Зазор слева и справа от окна аплета
VSPACE | Зазор сверху и снизу от окна аплета
NAME | Идентификатор аплета, который может быть использован другими аплетами, расположенными в одном и том же документе HTML, а также сценариями JavaScript
TITLE | Строка заголовка

Дополнительно между операторами <APPLET> и </APPLET> вы можете задать параметры аплета. Для этого используется оператор <PARAM>, который мы рассмотрим позже.

В нашем случае идентификатор NAME и имя двоичного файла заданы мастером проекта как "HelloApplet":

name="HelloApplet"
code="HelloApplet"

Параметр CODEBASE задает путь к каталогу локального диска:

codebase="file:/e:/sun/vol3/src/HelloApplet"

Когда вы будете размещать документ HTML на сервере, параметр CODEBASE необходимо изменить или удалить, если этот документ и аплет располагаются в одном каталоге. В любом случае, если параметр CODEBASE задан, он должен указывать адрес URL каталога с аплетом.


Новый текст
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Изменяем исходный текст аплета

Назад Вперед

Теперь давайте попробуем немного изменить исходный текст аплета, чтобы заставить его рисовать в своем окне текстовую строку "Hello, Java world".

Вначале измените исходный текст так, как это показано на рис. 6.

pic06sm.gif (2906 bytes) Рис. 6. Измененный исходный текст аплета HelloApplet

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Здесь мы намеренно внесли в исходный текст ошибку, чтобы показать, как Java WorkShop отреагирует на нее. Как видно из рисунка, сообщение об ошибке отображается на странице блокнота с названием Build. Текст сообщения гласит, что компилятор не смог найти определение класса Graphics, на который есть ссылка в девятой строке.

Добавим строку импортирования класса java.awt.*, как это показано в листинге 3.

Листинг 3. Файл HelloApplet.java (новый вариант)

import java.applet.Applet;
import java.awt.*;

public class HelloApplet extends Applet
{
  public String getAppletInfo()
  {
    return "HelloJava Applet";
  }
  public void paint(Graphics g)
  {
    g.drawString("Hello, Java world!",
      20, 20);
  }
}

Теперь исходный текст аплета транслируется без ошибок (рис. 7).

pic07sm.gif (2925 bytes) Рис. 7. Измененный исходный текст успешно оттранслирован

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Если запустить аплет на выполнение, в его окне будет нарисована строка "Hello, Java world" (рис. 8).

pic08.gif (2403 bytes)

Рис. 8. Теперь наш аплет "умеет" рисовать в своем окне текстовые строки


Метод paint
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Метод paint

Назад Вперед

Наиболее интересен для нас метод paint, который выполняет рисование в окне аплета. Вот его исходный текст:

public void paint(Graphics g)
{
  g.drawString("Hello, Java world!",
  20, 20);
}

Если посмотреть определение класса Applet, которое находится в файле JavaWorkshop20\JDK\src\java\applet\Applet.java, то в нем нет метода paint. В каком же классе определен этот метод?

Иерархия классов

Заглянем в документацию. Выберите из меню Help главного окна приложения Java WorkShop строку Java API Documentation. На экране появится окно браузера, встроенного в Java WorkShop. С помощью этого браузера вы сможете просматривать содержимое справочной системы.

В разделе Java API Packages выберите библиотеку классов java.applet, а затем в разделе Class Index - строку Applet. Вы увидите иерархию классов:

java.lang.Object
|
+---java.awt.Component
    |
    +---java.awt.Container
        |
        +---java.awt.Panel
            |
            +---java.applet.Applet

Из этой иерархии видно, что класс java.applet.Applet произошел от класса java.awt.Panel. Этот класс, в свою очередь, определен в библиотеке классов java.awt и произошел от класса java.awt.Container.

Продолжим наши исследования. В классе java.awt.Container снова нет метода paint, но сам этот класс создан на базе класса java.awt.Component.

Но и здесь метода paint нет. Этот метод определен в классе java.awt.Component, который, в свою очередь, произошел от класса java.lang.Object и реализует интерфейс java.awt.image.ImageObserver.

Таким образом мы проследили иерархию классов от класса java.applet.Applet, на базе которого создан наш аплет, до класса java.lang.Object, который является базовым для всех классов в Java.

Метод paint определен в классе java.awt.Component, но так как этот класс является базовым для класса Applet и для нашего класса HelloApplet, мы можем переопределить метод paint.

Вызов метода paint

Метод paint вызывается, когда необходимо перерисовать окно аплета. Если вы создавали приложения для операционной системы Windows, то наверняка знакомы с сообщением WM_PAINT, которое поступает в функцию окна приложения при необходимости его перерисовки.

Перерисовка окна приложения Windows и окна аплета обычно выполняется асинхронно по отношению к работе приложения или аплета. В любой момент времени аплет должен быть готов перерисовать содержимое своего окна.

Такая техника отличается о той, к которой вы, возможно, привыкли, создавая обычные программы для MS-DOS. Программы MS-DOS сами определяют, когда им нужно рисовать на экране, причем рисование может выполняться из разных мест программы. Аплеты, так же как и приложения Windows, выполняют рисование в своих окнах централизованно. Аплет делает это в методе paint, а приложение Windows - при обработке сообщения WM_PAINT.

Обратите внимание, что методу paint в качестве параметра передается ссылка на объект Graphics:

public void paint(Graphics g)
{
  . . .
}

По своему смыслу этот объект напоминает контекст отображения, с которым хорошо знакомы создатели приложений Windows. Контекст отображения - это как бы холст, на котором аплет может рисовать изображение или писать текст. Многочисленные методы класса Graphics позволяют задавать различные параметры холста, такие, например, как цвет или шрифт.

Наше приложение вызывает метод drawString, который рисует текстовую строку в окне аплета:

g.drawString("Hello, Java world!", 20, 20);

Вот прототип этого метода:

public abstract void drawString(String str,
  int x, int y);

Через первый параметр методу drawString передается текстовая строка в виде объекта класса String. Второй и третий параметр определяют, соответственно, координаты точки, в которой начнется рисование строки.

В какой координатной системе?

Аплеты используют систему координат, которая соответствует режиму отображения MM_TEXT, знакомому тем, кто создавал приложения Windows. Начало этой системы координат расположено в левом верхнем углу окна аплета, ось X направлена слева направо, а ось Y - сверху вниз (рис. 9).

pic09.gif (1786 bytes)

Рис. 9. Система координат, используемая методом drawString

На этом же рисунке показано, как метод drawString нарисует текстовую строку с координатами (xCoord, yCoord).


Метод getAppletInfo
Первый аплет
Создание проекта аплета
Исходный текст аплета
Методы в классе HelloApplet
Исходный текст документа HTML
Новый текст
Метод paint
Метод getAppletInfo

Метод getAppletInfo

Назад Вперед

Базовый класс Applet содержит определение метода getAppletInfo, возвращающее значение null. В нашем классе HelloApplet, который является дочерним по отношению к классу Applet, мы переопределили метод getAppletInfo из базового класса следующим образом:

public String getAppletInfo()
{
  return "HelloJava Applet";
}

Теперь метод getAppletInfo возвращает текстовую информацию об аплете в виде объекта класса String.

Этой информацией могут воспользоваться другие аплеты или сценарии JavaScript, например, для определения возможности взаимодействия с аплетом.


Рис. 1. Первая диалоговая панель мастера проектов

Для возврата сделайте щелчок мышью по рисунку

Рис. 1. Первая диалоговая панель мастера проектов


Рис. 2. Вторая диалоговая панель мастера проектов

Для возврата сделайте щелчок мышью по рисунку

Рис. 2. Вторая диалоговая панель мастера проектов


Рис. 4. Исходный текст аплета загружен в окно редактирования

Для возврата сделайте щелчок мышью по рисунку

Рис. 4. Исходный текст аплета загружен в окно редактирования


Рис. 6. Измененный исходный текст аплета HelloApplet

Для возврата сделайте щелчок мышью по рисунку

Рис. 6. Измененный исходный текст аплета HelloApplet


Рис. 7. Измененный исходный текст успешно оттранслирован

Для возврата сделайте щелчок мышью по рисунку

Рис. 7. Измененный исходный текст успешно оттранслирован


Рисование в окне аплета
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Рисование в окне аплета

Назад Вперед

В предыдущем разделе мы привели простейший пример аплета, который выполняет рисование текстовой строки в своем окне. Теперь мы расскажем вам о том, что и как может рисовать аплет.

Способ, которым аплет выполняет рисование в своем окне, полностью отличается от того, которым пользуются программы MS-DOS. Вместо того чтобы обращаться напрямую или через драйвер к регистрам видеоконтроллера, аплет пользуется методами из класса Graphics. Эти методы инкапсулируют все особенности аппаратуры, предоставляя в распоряжение программиста средство рисования, которое пригодно для любой компьютерной платформы.

Для окна аплета создается объект класса Graphics, ссылка на который передается методу paint. Раньше мы уже пользовались этим объектом, вызывая для него метод drawString, рисующий в окне текстовую строку. Объект, ссылка на который передается методу paint, и есть контекст отображения. Сейчас мы займемся контекстом отображения вплотную.


Контекст отображения
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Контекст отображения

Назад Вперед

Проще всего представить себе контекст отображения как полотно, на котором рисует художник. Точно так же как художник может выбирать для рисования различные инструменты, программист, создающий аплет Java, может выбирать различные методы класса Graphics и задавать различные атрибуты контекста отображения.

Методы класса Graphics

В качестве базового для класса Graphics (полное название класса java.awt.Graphics) выступает класс java.lang.Object.

Прежде всего мы приведем прототипы конструктора этого класса и его методов с краткими комментариями. Полное описание вы сможете найти в электронной документации, которая входит в комплект Java WorkShop.

Далее мы рассмотрим назначение основных методов, сгруппировав их по выполняемым функциям.

Конструктор

  • Graphics
protected Graphics();

Методы

  • clearRect

Стирание содержимого прямоугольной области

public abstract void clearRect(int x, int y,
  int width, int height);
  • clipRect

Задание области ограничения вывода

public abstract void clipRect(int x, int y,
  int width, int height);
  • copyArea

Копирование содержимого прямоугольной области

public abstract void copyArea(int x, int y,
  int width, int height, int dx, int dy);
  • create

Создание контекста отображения

public abstract Graphics create();

public Graphics create(int x, int y,
  int width, int height);
  • dispose

Удаление контекста отображения

public abstract void dispose();
  • draw3DRect

Рисование прямоугольной области с трехмерным выделением

public void draw3DRect(int x, int y,
  int width, int height, boolean raised);
  • drawArc

Рисование сегмента

public abstract void drawArc(int x, int y,
  int width, int height,
  int startAngle, int arcAngle);

Рисование сегмента

  • drawBytes

Рисование текста из массива байт

public void drawBytes(byte data[],
  int offset, int length, int x, int y);
  • drawChars

Рисование текста из массива символов

public void drawChars(char  data[],
  int offset, int length, int x, int y);
  • drawImage

Рисование растрового изображения

public abstract boolean	drawImage(Image img,
  int x, int y,
  Color bgcolor, ImageObserver observer);
public abstract boolean	drawImage(Image img,
  int x, int y,
  ImageObserver observer);

public abstract boolean	drawImage(Image img,
  int x, int y,
  int width, int height, Color bgcolor,
  ImageObserver observer);

public abstract boolean	drawImage(Image img,
  int x, int y,
  int width, int height,
  ImageObserver observer);
  • drawLine

Рисование линии

public abstract void drawLine(int x1, int y1,
  int x2, int y2);
  • drawOval

Рисование овала

public abstract void drawOval(int x, int y,
  int width, int height);
  • drawPolygon

Рисование многоугольника

public abstract void drawPolygon(
  int xPoints[],
  int yPoints[], int nPoints);

public void drawPolygon(Polygon p);
  • drawRect

Рисование прямоугольника

public void drawRect(int x, int y,
  int width, int height);
  • drawRoundRect

Рисование прямоугольника с круглыми углами

public abstract void drawRoundRect(
  int x, int y,
  int width, int height,
  int arcWidth, int arcHeight);
  • drawString

Рисование текстовой строки

public abstract void drawString(String str,
 int x, int y);
  • fill3DRect

Рисование заполненного прямоугольника с трехмерным выделением

public void fill3DRect(int x, int y,
  int width, int height, boolean raised);
  • fillArc

Рисование заполненного сегмента круга

public abstract void fillArc(int x,
    int y, int width,
    int height, int startAngle,
    int arcAngle);
  • fillOval

Рисование заполненного овала

public abstract void fillOval(int x, int y,
  int width, int height);
  • fillPolygon

Рисование заполненного многоугольника

public abstract void fillPolygon(
  int xPoints[],
  int yPoints[], int nPoints);
  • fillPolygon

Рисование заполненного многоугольника

public void fillPolygon(Polygon p);

public abstract void fillRect(int x, int y,
  int width, int height);
  • fillRoundRect

Рисование заполненного прямоугольника с круглыми углами

public abstract void fillRoundRect(
  int x, int y,
  int width, int height,
  int arcWidth, int arcHeight);
  • finalize

Прослеживание вызова метода dispose

public void finalize();
  • getClipRect

Определение границ области ограничения вывода

public abstract Rectangle getClipRect();
  • getColor

Определение цвета, выбранного в контекст отображения

public abstract Color getColor();
  • getFont

Определение шрифта, выбранного в контекст отображения

public abstract Font getFont();
  • getFontMetrics

Определение метрик текущего шрифта

public FontMetrics getFontMetrics();
  • getFontMetrics

Определение метрик заданного шрифта

public abstract FontMetrics
  getFontMetrics(Font f);
  • setColor

Установка цвета для рисования в контексте отображения

public abstract void setColor(Color c);
  • setFont

Установка текущего шрифта в контексте отображения

public abstract void setFont(Font font);
  • setPaintMode

Установка режима рисования

Метод setPaintMode устанавливает в контексте отображения режим рисования, при котором выполняется замещение изображения текущим цветом, установленном в контексте отображения.

public abstract void setPaintMode();
  • setXORMode

Установка маски для рисования

Задавая маску для рисования при помощи метода setXORMode, вы можете выполнить при рисовании замещение текущего цвета на цвет, указанный в параметре метода, и наоборот, цвета, указанного в параметре метода, на текущий.

Все остальные цвета изменяются непредсказуемым образом, однако эта операция обратима, если вы нарисуете ту же самую фигуру два раза на одном и том же месте.

public abstract void setXORMode(Color c1);
  • translate

Сдвиг начала системы координат

Метод translate сдвигает начало системы координат в контексте отображения таким образом, что оно перемещается в точку с координатами (x, y), заданными через параметры метода:

public abstract void translate(int x, int y);
  • toString

Получение текстовой строки, представляющейданный контекст отображения

public String toString();


Установка атрибутов
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Установка атрибутов контекста отображения

Назад Вперед

Изменяя атрибуты контекста отображения, приложение Java может установить цвет для рисования графических изображений, таких как линии и многоугольники, шрифт для рисования текста, режим рисования и маску. Возможен также сдвиг начала системы координат.

Выбор цвета

Изменение цвета, выбранного в контекст отображения, выполняется достаточно часто. В классе Graphics для изменения цвета определен метод setColor, прототип которого представлен ниже:

public abstract void setColor(Color c);

В качестве параметра методу setColor передается ссылка на объект класса Color, с помощью которого можно выбрать тот или иной цвет.

Как задается цвет?

Для этого можно использовать несколько способов.

Прежде всего, вам доступны статические объекты, определяющие фиксированный набор основных цветов:

Объект | Цвет
public final static Color black; | черный
public final static Color blue; | голубой
public final static Color cyan; | циан
public final static Color darkGray; | темно-серый
public final static Color gray; | серый
public final static Color green; | зеленый
public final static Color lightGray; | светло-серый
public final static Color magenta; | малиновый
public final static Color orange; | оранжевый
public final static Color pink; | розовый
public final static Color red; | красный
public final static Color white; | белый
public final static Color yellow; | желтый

Этим набором цветов пользоваться очень просто:

public void paint(Graphics g)
{
  g.setColor(Color.yellow);
  g.drawString("Hello, Java world!",
   10, 20);
  . . .
}

Здесь мы привели фрагмент исходного текста метода paint, в котором в контексте отображения устанавливается желтый цвет. После этого метод drawString выведет текстовую строку " Hello, Java world!" желтым цветом.

Если необходима более точная установка цвета, вы можете воспользоваться одним из трех конструкторов объекта Color:

public Color(float r, float g, float b);
public Color(int r, int g, int b);
public Color(int rgb);

Первые два конструктора позволяют задавать цвет в виде совокупности значений трех основных цветовых компонент - красной, желтой и голубой (соответственно, параметры r, g и b). Для первого конструктора диапазон возможных значений компонент цвета находится в диапазоне от 0.0 до 1.0, а для второго - в диапазоне от 0 до 255.

Третий конструктор также позволяет задавать отдельные компоненты цвета, однако они должны быть скомбинированы в одной переменной типа int. Голубая компонента занимает биты от 0 до 7, зеленая - от 8 до 15, красная - от 16 до 23.

Ниже мы привели пример выбора цвета с помощью конструктора, передав ему три целочисленных значения цветовых компонент:

g.setColor(new Color(0, 128, 128));

В классе Color определено еще несколько методов, которые могут оказаться вам полезными:

Метод | Описание
public Color brighter (); | Установка более светлого варианта того же цвета
public Color darker (); | Установка более темного варианта того же цвета
public boolean equals (Object obj); | Проверка равенства цветов текущего объекта и объекта, заданного параметром
public int getBlue (); | Определение голубой компоненты цвета (в диапазоне от 0 до 255)
public int getRed (); | Определение красной компоненты цвета (в диапазоне от 0 до 255)
public int getGreen (); | Определение зеленой компоненты цвета (в диапазоне от 0 до 255)
getHSBColor (float h, float s, float b); | Определение компонент оттенка, насыщенности и яркости (схема HSB)
public int getRGB (); | Определение компонент RGB для цвета, выбранного в контекст отображения
public static int HSBtoRGB (float hue, float saturation, float brightness); | Преобразование цветового представления из схемы HSB в схему RGB
public static float[] RGBtoHSB (int r, int g, int b, float hsbvals[]); | Преобразование, обратное выполняемому предыдущей функцией
public String toString (); | Получение текстовой строки названия цвета

Второй способ установки цвето фона и изображения заключается в вызове методов setBackground и setForeground, например:

setBackground(Color.yellow);
setForeground(Color.black);

Здесь мы устанавливаем для окна аплета желтый цвет фона и черный цвет изображения.

Выбор шрифта

С помощью метода setFont из класса Graphics вы можете выбрать в контекст отображения шрифт, который будет использоваться методами drawString, drawBytes и drawChars для рисования текста. Вот прототип метода setFont:

public abstract void setFont(Font font);

В качестве параметра методу setFont следует передать объект класса Font.

Класс Font

Приведем краткое перечисление полей, конструкторов и методов этого класса.

Поля класса

  • name
protected String name;
  • size
protected int size;
  • style
protected int style;

Битовые маски стиля шрифта

  • BOLD
public final static int BOLD;
  • ITALIC
public final static int ITALIC;
  • PLAIN
public final static int PLAIN;

Конструкторы

public Font(String name,
  int style, int size);

Методы

  • equals

Сравнение шрифтов

public boolean equals(Object obj);
  • getFamily

Определение названия семейства шрифтов

public String getFamily();
  • getFont

Получение шрифта по его характеристикам

public static Font getFont(String  nm);
public static Font getFont(String  nm,
  Font  font);
  • getName

Определение названия шрифта

public String getName();
  • getSize

Определение размера шрифта

public int getSize();
  • getStyle

Определение стиля шрифта

public int getStyle();
  • hashCode

Получение хэш-кода шрифта

public int hashCode();
  • isBold

Определение жирности шрифта

public boolean isBold();
  • isItalic

Проверка, является ли шрифт наклонным

public boolean isItalic();
  • isPlain

Проверка, есть ли шрифтовое выделение

public boolean isPlain();
  • toString

Получение текстовой строки для объекта

public String toString();

Создавая шрифт конструктором Font, вы должны указать имя, стиль и размер шрифта.

В качестве имени можно указать, например, такие строки как Helvetica или Courier. Учтите, что в системе удаленного пользователя, загрузившего ваш аплет, может не найтись шрифта с указанным вами именем. В этом случае браузер заменит его на наиболее подходящий (с его точки зрения).

Стиль шрифта задается масками BOLD, ITALIC и PLAIN, которые можно комбинировать при помощи логической операции "ИЛИ":

Маска | Описание
BOLD | Утолщенный шрифт
ITALIC | Наклонный шрифт
PLAIN | Шрифтовое выделение не используется

Что же касается размера шрифта, то он указывается в пикселах.


Определение атрибутов
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Определение атрибутов контекста отображения

Назад Вперед

Ряд методов класса Graphics позволяет определить различные атрибуты контекста отображения, например, цвет, выбранный в контекст отображения или метрики текущего шрифта, которым выполняется рисование текста.

Рассмотрим методы, позволяющие определить атрибуты контекста отображения.

Определение границ области ограничения вывода

С помощью метода clipRect, о котором мы расскажем чуть позже, вы можете определить в окне аплета область ограничения вывода прямоугольной формы. Вне этой области рисование графических изображений и текста не выполняется.

Метод getClipRect позволяет вам определить координаты текущей области ограничения, заданной в контексте отображения:

public abstract Rectangle getClipRect();

Метод возвращает ссылку на объект класса Rectangle, который, в частности, имеет поля класса с именами x, y, height и width. В этих полях находится, соответственно, координаты верхнего левого угла, высота и ширина прямоугольной области.

Определение цвета, выбранного в контекст отображения

Метод getColor возвращает ссылку на объект класса Color, представляющий текущий цвет, выбранный в контекст отображения:

public abstract Color getColor();

Определение шрифта, выбранного в контекст отображения

С помощью метода getFont, возвращающего ссылку на объект класса Font, вы можете определить текущий шрифт, выбранный в контекст отображения:

public abstract Font getFont();

Определение метрик текущего шрифта

Несмотря на то что вы можете заказать шрифт с заданным именем и размером, не следует надеяться, что навигатор выделит вам именно такой шрифт, какой вы попросите. Для правильного размещения текста и других изображений в окне аплета вам необходимо знать метрики реального шрифта, выбранного навигатором в контекст отображения.

Метрики текущего шрифта в контексте отображения вы можете узнать при помощи метода getFontMetrics, прототип которого приведен ниже:

public FontMetrics getFontMetrics();

Метод getFontMetrics возвращает ссылку на объект класса FontMetrics. Ниже мы привели список наиболее важных методов этого класса, предназначенных для получения отдельных параметров шрифта:

Метод | Описание
public Font getFont(); | Определение шрифта, который описывается данной метрикой
public int bytesWidth(byte data[], int off, int len); | Метод возвращает ширину строки символов, расположенных в массиве байт data. Параметры off и len задают, соответственно, смещение начала строки в массиве и ее длину
public int charsWidth(char data[], int off, int len); | Метод возвращает ширину строки символов, расположенных в массиве символов data. Параметры off и len задают, соответственно, смещение начала строки в массиве и ее длину
public int charWidth(char ch); | Метод возвращает ширину заданного символа
public int charWidth(int ch); | Метод возвращает ширину заданной строки символов
public int getAscent(); | Определение расстояния от базовой линии до верхней выступающей части символов
public int getDescent(); | Определение расстояния от базовой линии до нижней выступающей части символов
public int getLeading(); | Расстояние между строками текста
public int getHeight(); | Определение полной высоты символов, выполняется по формуле: getLeading() + getAscent() + getDescent()
public int getMaxAdvance(); | Максимальная ширина символов в шрифте
public int getMaxAscent(); | Максимальное расстояние от базовой линии до верхней выступающей части символов для символов данного шрифта
public int getMaxDescent(); | Максимальное расстояние от базовой линии до нижней выступающей части символов для символов данного шрифта
public int[] getWidths(); | Массив, в котором хранятся значения ширины первых 256 символов в шрифте
public int stringWidth(String str); | Ширина строки, передаваемой методу в качестве параметра
public String toString(); | Текстовая строка, представляющая данную метрику шрифта

Обратите внимание на метод stringWidth, позволяющий определить ширину текстовой строки. Заметим, что без этого метода определение ширины текстовой строки было бы непростой задачей, особенно если шрифт имеет переменную ширину символов.

Для определения полной высоты строки символов вы можете воспользоваться методом getHeight.

Определение метрик заданного шрифта

Метод getFontMetrics с параметром типа Font позволяет определить метрики любого шрифта, передаваемого ему в качестве параметра:

public abstract FontMetrics
  getFontMetrics(Font f);

В отличие от нее метод getFontMetrics без параметров возвращает метрики текущего шрифта, выбранного в контекст отображения.


Рисование фигур
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Рисование геометрических фигур

Назад Вперед

В этом разделе мы опишем методы класса Graphics, предназначенные для рисования элементарных геометрических фигур, таких как линии, прямоугольники, окружности и так далее.

Линии

Для того чтобы нарисовать прямую тонкую сплошную линию, вы можете воспользоваться методом drawLine, прототип которого приведен ниже:

public abstract void drawLine(int x1,
  int y1,int x2, int y2);

Концы линии имеют координаты (x1, y1) и (x2, y2), как это показано на рис. 1.

pic01.gif (2176 bytes)

Рис. 1. Рисование прямой линии

К сожалению, в контексте отображения не предусмотрены никакие атрибуты, позволяющие нарисовать пунктирную линию или линию увеличенной толщины.

Прямоугольники и квадраты

Среди методов класса Graphics есть несколько, предназначенных для рисования прямоугольников. Первый из них, с именем drawRect, позволяет нарисовать прямоугольник, заданный координатами своего левого верхнего угла, шириной и высотой:

public void drawRect(int x, int y,
  int width, int height);

Параметры x и y задают, соответственно, координаты верхнего левого угла, а параметры width и height - высоту и ширину прямоугольника (рис. 2).

pic02.gif (2472 bytes)

Рис. 2. Рисование прямоугольника

В отличие от метода drawRect, рисующего только прямоугольную рамку, метод fillRect рисует заполненный прямоугольник. Для рисования и заполнения прямоугольника используется цвет, выбранный в контекст отображения (рис. 3).

pic03.gif (3126 bytes)

Рис. 3. Рисование заполненного прямоугольника

Прототип метода fillRect приведен ниже:

public abstract voidfillRect(int x, int y,
  int width, int height);

Метод drawRoundRect позволяет нарисовать прямоугольник с закругленными углами:

public abstract void drawRoundRect(int x,
  int y, int width,
  int height, int arcWidth, int arcHeight);

Параметры x и y определяют координаты верхнего левого угла прямоугольника, параметры width и height задают, соответственно его ширину и высоту.

Размеры эллипса, образующего закругления по углам, вы можете задать с помощью параметров arcWidth и arcHeight. Первый из них задает ширину эллипса, а второй - высоту (рис. 4).

pic04.gif (3197 bytes)

Рис. 4. Рисование прямоугольника с закругленными углами

Метод fillRoundRect позволяет нарисовать заполненный прямоугольник с закругленными углами (рис. 5).

pic05.gif (3887 bytes)

Рис. 5. Рисование заполненного прямоугольника с закругленными углами

Назначение параметров этого метода аналогично назначению параметров только что рассмотренного метода drawRoundRect:

public abstract voidfillRoundRect(int x,
 int y,
 int width, int height,
 int arcWidth, int arcHeight);

Метод fill3Drect предназначен для рисования выступающего или западающего прямоугольника:

public void fill3DRect(int x, int y,
  int width, int height, boolean raised);

Если значение параметра raised равно true, рисуется выступающий прямоугольник, если false - западающий. Назначение остальных параметров аналогично назначению параметров метода drawRect.

Многоугольники

Для рисования многоугольников в классе Graphics предусмотрено четыре метода, два из которых рисуют незаполненные многоугольники, а два - заполненные.

Первый метод рисует незаполненный многоугольник, заданный массивами координат по осям X и Y:

public abstract voiddrawPolygon(
  int xPoints[],
  int yPoints[], int nPoints);

Через параметры xPoints и yPoints передаются, соответственно, ссылки на массивы координат по оис X и Y. Параметр nPoints задает количество точек в массивах.

На рис. 6 показан многоугольник, нарисованный методом drawPolygon.

pic06.gif (2719 bytes)

Рис. 6. Многоугольник, нарисованный методом drawPolygon

В этом многоугольнике шесть вершин с координатами от (x0, y0) до (x5, y5), причем для того чтобы он стал замкнутым, координаты первой и последней вершины совпадают.

Второй метод также рисует незаполненный многоугольник, однако в качестве параметра методу передается ссылка на объект Polygon:

public void drawPolygon(Polygon p);

Класс Polygon достаточно прост. Приведем описание его полей, конструкторов и методов:

Поля класса

  • npoints

Количество вершин

public int npoints;
  • xpoints

Массив координат по оси X

public int xpoints[];
  • ypoints

Массив координат по оси Y

public int ypoints[]

Конструкторы

public Polygon ();
public Polygon(int xpoints[],
  int ypoints[], int npoints);

Методы

  • addPoint

Добавление вершины

public void addPoint(int x, int y);
  • getBoundingBox

Получение координат охватывающего прямоугольника

public Rectangle getBoundingBox();
  • inside

Проверка, находится ли точка внутри многоугольника

public boolean inside(int x, int y);

Ниже мы показали фрагмент кода, в котором создается многоугольник, а затем в него добавляется несколько точек. Многоугольник рисуется методом drawPolygon:

Polygon p = new Polygon();
p.addPoint(270, 239);
p.addPoint(350, 230);
p.addPoint(360, 180);
p.addPoint(390, 160);
p.addPoint(340, 130);
p.addPoint(270, 239);
g.drawPolygon(p);

Если вам нужно нарисовать заполненный многоугольник (рис. 7), то для этого вы можете воспользоваться методами, приведенными ниже:

public abstract void fillPolygon(
 int xPoints[],
 int yPoints[], int nPoints);

public void fillPolygon(Polygon p);

Первый из этих методов рисует многоугольник, координаты вершин которого заданы в массивах, второй - получая объект класса Polygon в качестве параметра.

pic07.gif (3128 bytes)

Рис. 7. Многоугольник, нарисованный методом fillPolygon

Овалы и круги

Для рисования окружностей и овалов вы можете воспользоваться методом drawOval:

public abstract void drawOval(
  int x, int y,
  int width, int height);

Параметры этого методы задают координаты и размеры прямоугольника, в который вписывается рисуемый овал (рис. 8).

pic08.gif (2591 bytes)

Рис. 8. Рисование овала

Метод fillOval предназначен для рисования заполненного овала (рис. 9). Назначение его параметров аналогично назначению параметров метода drawOval:

public abstract voidfillOval(
  int x, int y,
  int width, int height);

pic09.gif (3122 bytes)

Рис. 9. Рисование заполненного овала

Сегменты

Метод drawArc предназначен для рисования незаполненного сегмента (рис. 10). Прототип этого метода приведен ниже:

public abstract void drawArc(
 int x, int y,
 int width, int height,
 int startAngle, int arcAngle);

pic10.gif (3409 bytes)

Рис. 10. Рисование незаполненного сегмента

Параметры x, y, width и height задают координаты прямоугольника, в который вписан сегмент.

Параметры startAngle и arcAngle задаются в градусах. Они определяют, соответственно, начальный угол и угол разворота сегмента.

Для того чтобы нарисовать заполненный сегмент, вы можете воспользоваться методом fillArc:

public abstract voidfillArc(int x, int y,
  int width, int height,
  int startAngle, int arcAngle);

Задание области ограничения

Если для окна аплета задать область ограничения, то рисование будет возможно только в пределах этой области. Область ограничения задается методом clipRect, прототип которого мы привели ниже:

public abstract void clipRect(
 int x, int y,
 int width, int height);

Параметры x, y, width и height задают координаты прямоугольной области ограничения.

Копирование содержимого прямоугольной области

Метод copyArea позволяет скопировать содержимое любой прямоугольной области окна аплета:

public abstract voidcopyArea(
 int x, int y,
 int width, int height, int dx, int dy);

Параметры x, y, width и height задают координаты копируемой прямоугольной области. Область копируется в другую прямоугольную область такого же размера, причем параметры dx и dy определяют координаты последней.


Аплет Draw
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Аплет Draw

Назад Вперед

В этом разделе мы приведем исходные тексты аплета Draw, в которых демонстрируется использование различных функций рисования.

На рис. 11 показано окно этого аплета.

pic11.gif (4305 bytes)

Рис. 11. Окно аплета Draw

В верхней части окна мы вывели список вех шрифтов, доступных аплету, а также примеры оформления строки Test string с использованием этих шрифтов.

В нижней части окна нарисовано несколько геометрических фигур.


Исходные тексты
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Исходные тексты аплета Draw

Назад Вперед

Исходные тексты аплета Draw вы найдете в листинге 1.

Листинг 1. Файл draw.java

import java.applet.*;
import java.awt.*;

public class draw extends Applet
{
  Toolkit tk;
  String szFontList[];
  FontMetrics fm;
  int yStart = 20;
  int yStep;
  String parm_TestString;

  public void init()
  {
    tk = Toolkit.getDefaultToolkit();
    szFontList = tk.getFontList();
    parm_TestString =
      getParameter("TestString");
  }

  public String getAppletInfo()
  {
    return "Name: draw";
  }

  public void paint(Graphics g)
  {
    int yDraw;
    Dimension dimAppWndDimension = getSize();

    g.clearRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);

    g.setColor(Color.yellow);
    g.fillRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);

    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);

    fm = g.getFontMetrics();
    yStep = fm.getHeight();

    for(int i = 0; i < szFontList.length; i++)
    {
      g.setFont(new Font("Helvetica",
        Font.PLAIN, 12));
      g.drawString(szFontList[i], 10,
        yStart + yStep * i);

      fm = g.getFontMetrics();
      yStep = fm.getHeight();

      g.setFont(new Font(szFontList[i],
        Font.PLAIN, 12));
      g.drawString(parm_TestString,
        100, yStart + yStep * i);
    }

    yDraw = yStart + yStep * szFontList.length
      + yStep;

    Polygon p = new Polygon();

    p.addPoint(70, yDraw);
    p.addPoint(150, yDraw + 30);
    p.addPoint(160, yDraw + 80);
    p.addPoint(190, yDraw + 60);
    p.addPoint(140, yDraw + 30);
    p.addPoint(70, yDraw + 39);

    g.drawPolygon(p);

    g.setColor(Color.red);
    g.drawRect(10, yDraw + 85, 200, 100);

    g.setColor(Color.black);
    g.drawArc(10, yDraw + 85,
      200, 100, -50, 320);
  }

  public String[][] getParameterInfo()
  {
    String[][] info =
    {
      {
    "TestString", "String", "Test string"
      }
    };
    return info;
  }
}

Метод init

При инициализации аплета метод init извлекает список доступных шрифтов и принимает значение параметра TestString, передаваемое аплету в документе HTML.

Извлечение списка шрифтов

Процедура извлечения списка доступных шрифтов достаточно проста и выполняется следующим образом:

Toolkit tk;
String szFontList[];
  . . .
tk = Toolkit.getDefaultToolkit();
szFontList = tk.getFontList();

Аплет вызывает статический метод getDefaultToolkit из класса Toolkit и затем, пользуясь полученной ссылкой, извлекает список шрифтов, записывая его в массив szFontList.

Для чего еще можно использовать класс Toolkit?

Класс Toolkit является абстрактным суперклассом для всех реализаций AWT. Порожденные от него классы используются для привязки различных компонент конкретных реализаций.

Создавая свои аплеты, вы будете редко прибегать к услугам этого класса. Однако в нем есть несколько полезных методов, прототипы которых мы перечислим ниже:

  • getDefaultToolkit

Получение ссылки на Toolkit

public static Toolkit getDefaultToolkit();
  • getColorModel

Определение текущей цветовой модели, выбранной в контекст отображения

public abstract ColorModel getColorModel();
  • getFontList

Получение списка шрифтов, доступных аплету

public abstract String[] getFontList();
  • getFontMetrics

Получение метрик заданного шрифта

public abstract FontMetrics
  getFontMetrics(Font font);
  • getImage

Получение растрового изображения по имени файла

public abstract Image
  getImage(String filename);
  • getImage

Получение растрового изображения по адресу URL

public abstract Image getImage(URL  url);
  • getScreenResolution

Определение разрешения экрана в точках на дюйм

public abstract int getScreenResolution();
  • getScreenSize

Размеры экрана в пикселах

public abstract Dimension getScreenSize();
  • prepareImage

Подготовка растрового изображения для вывода

public abstract boolean prepareImage(
  Image image,
  int width, int height,
  ImageObserver observer);
  • sync

Синхронизация состояния Toolkit

public abstract void sync();

Наиболее интересны, с нашей точки зрения, методы getFontList, getScreenResolution и getScreenSize, с помощью которых аплет может, соответственно, получить список шрифтов, определить разрешение и размер экрана. Последние два параметра позволяют сформировать содержимое окна аплета оптимальным образом исходя из объема информации, который может в нем разместиться.

Получение значения параметров

До сих пор наши аплеты не получали параметров из документов HTML, в которые мы их встраивали.

Конечно, все константы, текстовые строки, адреса URL и другую информацию можно закодировать непосредственно в исходном тексте аплета, однако, очевидно, это очень неудобно.

Пользуясь операторами <PARAM>, расположенными в документе HTML сразу после оператора <APPLET>, можно передать аплету произвольное количество параметров, например, в виде текстовых строк:

<applet
    code=MyApplet.class
    id=MyApplet
     . . .
    width=320
    height=240 >
    <param name=ParamName1 value="Value 1">
    <param name=ParamName2 value="Value 2">
    <param name=ParamName3 value="Value 3">
    <param name=ParamName4 value="Value 4">
     . . .
</applet>

Здесь через параметр NAME оператора <PARAM> передается имя параметра аплета, а через параметр VALUE - значение соответствующего параметра.

Как параметр может получить значение параметров?

Для получения значения любого параметра аплет должен использовать метод getParameter. В качестве единственного параметра этому методу передается имя параметра аплета в виде строки типа String, например:

parm_TestString = getParameter("TestString");

Обычно в аплете также определяется метод getParameterInfo, возвращающий информацию о параметрах. Вот исходный текст этого метода для нашего аплета Draw:

public String[][] getParameterInfo()
{
  String[][] info =
  {
    {
      "TestString", "String", "Test string"
    }
  };
  return info;
}

Метод getParameterInfo возвращает массив массивов текстовых строк. Первая строка указывает имя параметра, вторая - тип передаваемых через него данных, а третья - значение параметра по умолчанию.

Метод paint

Первым делом метод paint определяет размеры окна аплета, вызывая для этого метод getSize:

Dimension dimAppWndDimension = getSize();

Метод getSize возвращает ссылку на объект класса Dimension, хранящий высоту и ширину объекта:

  • height

Высота

public int height;
  • width

Ширина

public int width;

В классе Dimension предусмотрено три конструктора и один метод:

public Dimension();
public Dimension(Dimension  d);
public Dimension(int width, int height);
  • toString

Получение строки, представляющей класс

public String toString();

После определения размеров окна аплета метод paint стирает содержимое всего окна:

g.clearRect(0, 0,
  dimAppWndDimension.width  - 1,
  dimAppWndDimension.height - 1);

Далее в контексте отображения устанавливается желтый цвет:

g.setColor(Color.yellow);

Этим цветом заполняется внутренняя область окна аплета, для чего применяется метод fillRect:

g.fillRect(0, 0,
  dimAppWndDimension.width  - 1,
  dimAppWndDimension.height - 1);

Затем метод paint устанавливает в контексте отображения черный цвет и рисует тонкую черную рамку вокруг окна аплета:

g.setColor(Color.black);
g.drawRect(0, 0,
  dimAppWndDimension.width  - 1,
  dimAppWndDimension.height - 1);

На следующем этапе мы получаем метрики текущего шрифта, выбранного в контекст отображения:

fm = g.getFontMetrics();

Пользуясь этими метриками, мы определяем высоту символов текущего шрифта и записываем ее в поле yStep:

yStep = fm.getHeight();

После этого метод paint запускает цикл по всем шрифтам, установленным в системе:

for(int i = 0; i < szFontList.length; i++)
{
  . . .
}

Количество доступных шрифтов равно размеру массива szFontList, которое вычисляется как szFontList.length.

Метод paint выписывает в окне аплета название каждого шрифта, устанавливая для этого шрифт Helvetica размером 12 пикселов:

g.setFont(new Font("Helvetica",
  Font.PLAIN, 12));
g.drawString(szFontList[i],
  10, yStart + yStep * i);

Смещение каждой новой строки с названием шрифта вычисляется исходя из высоты символов установленного шрифта:

fm = g.getFontMetrics();
yStep = fm.getHeight();

После названия шрифта метод paint рисует в окне аплета текстовую строку parm_TestString, полученную через параметр с именем "TestString":

g.setFont(new Font(szFontList[i],
  Font.PLAIN, 12));
g.drawString(parm_TestString,
  100, yStart + yStep * i);

Перед тем как перейти к рисованию геометрических фигур, метод paint запоминает в поле yDraw координату последней строки названия шрифта, сделав отступ высотой yStep :

int yDraw;
yDraw = yStart +
  yStep * szFontList.length + yStep;

Первая фигура, которую рисует наш аплет, это многоугольник.

Мы создаем многоугольник как объект класса Polygon:

Polygon p = new Polygon();

В этот объект при помощи метода addPointдобавляется несколько точек:

p.addPoint(70, yDraw);
p.addPoint(150, yDraw + 30);
p.addPoint(160, yDraw + 80);
p.addPoint(190, yDraw + 60);
p.addPoint(140, yDraw + 30);
p.addPoint(70, yDraw + 39);

После добавления всех точек метод paint рисует многоугольник, вызывая для этого метод drawPolygon:

g.drawPolygon(p);

Затем мы устанавливаем в контексте отображения красный цвет и рисуем прямоугольник:

g.setColor(Color.red);
g.drawRect(10, yDraw + 85, 200, 100);

Затем метод paint вписывает в этот прямоугольник сегмент окружности:

g.setColor(Color.black);
g.drawArc(10, yDraw + 85,
  200, 100, -50, 320);

Документ HTML для аплета Draw

Документ HTML для аплета Draw не имеет никаких особенностей. Он представлен в листинге 2.

Листинг 2. Файл draw.tmp.html

<applet
   name="draw"
   code="draw"
   codebase="file:/e:/Sun/Articles/vol4/src/draw"
   width="250"
   height="350"
   align="Top"
   alt="If you had a java-enabled browser,
 you would see an applet here."
>
<param name="TestString" value="Test string">
   <hr>If your browser recognized the applet tag,
   you would see an applet here.<hr>
</applet>


Проект аплета
Рисование в окне аплета
Контекст отображения
Установка атрибутов
Определение атрибутов
Рисование фигур
Аплет Draw
Исходные тексты
Проект аплета

Проект для аплета Draw

Назад Вперед

Подготовьте файлы проекта аплета Draw, скопировав их из предыдущего раздела в какой-нибудь каталог. Затем запустите мастер проектов и в соответствующей диалоговой панели укажите путь к этому каталогу (рис. 12).

pic12sm.gif (1779 bytes) Рис. 12. Указание пути к каталогу с исходными файлами

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Так как в каталоге уже есть файлы, вы должны включить переключатель Yes и затем нажать кнопку Next.

После этого вы увидите на экране диалоговую панель, показанную на рис. 13.

pic13sm.gif (1801 bytes) Рис. 13. Добавление к проекту существующих файлов

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Здесь вам нужно нажать кнопку Add All in Directory. Как только вы это сделаете, в списке файлов Project Files появится имя файла draw.java, подготовленного вами заранее.

На следующем шаге вам опять нужно нажать кнопку Next и проследить, чтобы имя главного класса аплета, отображаемое в диалоговой панели, показанной на рис. 14, было draw.

pic14sm.gif (1610 bytes) Рис. 14. Задание имени главного класса

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Нажав кнопку Finish, вы можете завершить формирование проекта.

Hаш аплет принимает из документа HTML один параметр с именем TestString. Для добавления параметров вам нужно открыть окно менеджера проектов, выбрав из меню Project строку Show Project Manager. В этом окне проект draw должен быть текущим.

Выделите его курсором мыши в окне Java WorkShop Project Manager и из меню Project этого окна выберите строку Edit. Вы увидите блокнот Project Edit, с помощью которого можно изменять различные параметры проекта. Откройте в этом блокноте страницу Run (рис. 15).

pic15sm.gif (2214 bytes) Рис. 15. Добавление параметра TestString

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

В полях Name и Value введите, соответственно, имя параметра и значение параметра по умолчанию, а затем нажмите кнопку Add. Добавленный вами параметр появится в списке Parameters. Теперь вам осталось только нажать кнопку OK.


Рис. 12. Указание пути к каталогу с исходными файлами

Для возврата сделайте щелчок мышью по рисунку

Рис. 12. Указание пути к каталогу с исходными файлами


Рис. 13. Добавление к проекту существующих файлов

Для возврата сделайте щелчок мышью по рисунку

Рис. 13. Добавление к проекту существующих файлов


Рис. 14. Задание имени главного класса

Для возврата сделайте щелчок мышью по рисунку

Рис. 14. Задание имени главного класса


Рис. 15. Добавление параметра TestString

Для возврата сделайте щелчок мышью по рисунку

Рис. 15. Добавление параметра TestString


События
События
Обработка событий
События от мыши
Аплет LineDraw
Исходный текст
Описание текста

События

Назад Вперед

От аплетов Java было бы немного толку, если бы они не умели обрабатывать информацию, поступающую от мыши и клавиатуры. К счастью, такая обработка предусмотрена и она выполняется достаточно просто.

Когда пользователь выполняет операции с мышью или клавиатурой в окне аплета, возникают события, которые передаются соответствующим методам класса Applet. Переопределяя эти методы, вы можете организовать обработку событий, возникающих от мыши или клавиатуры.

Если вы создавали приложения для операционной системы Microsoft Windows, здесь для вас нет ничего нового - вспомните, как вы обрабатывали сообщение WM_LBUTTONDOWN или WM_CHAR. Когда пользователь выполнял действие с мышью или клавиатурой в окне приложения, функция этого окна получала соответствующее сообщение. Методы класса Applet, обрабатывающие события от мыши и клавиатуры, являются аналогами обработчиков указанных сообщений.

Заметим, что аплеты имеют дело только с левой клавишей мыши. В текущей версии Java вы не можете никаким образом задействовать в аплете правую или среднюю клавишу мыши.


Обработка событий
События
Обработка событий
События от мыши
Аплет LineDraw
Исходный текст
Описание текста

Как обрабатываются события

Назад Вперед

Когда возникает событие, управление получает метод handleEvent из класса Component. Класс Applet является дочерним по отношению к классу Component.

Прототип метода handleEvent мы привели ниже:

public boolean handleEvent(Event evt);

В качестве параметра методу handleEvent передается объект класса Event, который содержит всю информацию о событии. По содержимому полей класса Event вы можете определить координаты курсора мыши в момент, когда пользователь нажал клавишу, отличить одинарный щелчок от двойного и так далее.

Ниже мы привели список полей класса Event, которые вы можете проанализировать:

Поле | Описание
public Object arg; | Произвольный аргумент события, значение которого зависит от типа события
public int clickCount; | Это поле имеет значение только для события с типом MOUSE_DOWNMOUSE_DOWN и содержит количество нажатий на клавишу мыши. Если пользователь сделал двойной щелчок мышью, в это поле будет записано значение 2
public Event evt; | Следующее событие в связанном списке
public int id; | Тип события. Ниже мы перечислим возможные значения для этого поля
public int key; | Код нажатой клавиши (только для события, созданного при выполнении пользователем операции с клавиатурой)
public int modifiers; | Состояние клавиш модификации <Alt>, <Ctrl>, <Shift>
public Object target; | Компонент, в котором произошло событие
public long when; | Время, когда произошло событие
public int x; | Координата по оси X
public int y; | Координата по оси Y

Поле id (тип события) может содержать следующие значения:

Значение | Тип события
ACTION_EVENT | Пользователь хочет, чтобы произошло некоторое событие
GOT_FOCUS | Компонент (в нашем случае окно аплета) получил фокус ввода. О фокусе ввода вы узнаете из раздела, посвященного работе с клавиатурой
KEY_ACTION | Пользователь нажал клавишу типа "Action"
KEY_ACTION_RELEASE | Пользователь отпустил клавишу типа "Action"
KEY_PRESS | Пользователь нажал обычную клавишу
KEY_RELEASE | Пользователь отпустил обычную клавишу
LIST_DESELECT | Отмена выделения элемента в списке
LIST_SELECT | Выделение элемента в списке
LOAD_FILE | Загрузка файла
LOST_FOCUS | Компонент потерял фокус ввода
MOUSE_DOWN | Пользователь нажал клавишу мыши
MOUSE_DRAG | Пользователь нажал клавишу мыши и начал выполнять перемещение курсора мыши
MOUSE_ENTER | Курсор мыши вошел в область окна аплета
MOUSE_EXIT | Курсор мыши покинул область окна аплета
MOUSE_MOVE | Пользователь начал выполнять перемещение курсора мыши, не нажимая клавишу мыши
MOUSE_UP | Пользователь отпустил клавишу мыши
SAVE_FILE | Сохранение файла
SCROLL_ABSOLUTE | Пользователь переместил движок полосы просмотра в новую позицию
SCROLL_LINE_DOWN | Пользователь выполнил над полосой просмотра операцию сдвига на одну строку вниз
SCROLL_LINE_UP | Пользователь выполнил над полосой просмотра операцию сдвига на одну строку вверх
SCROLL_PAGE_DOWN | Пользователь выполнил над полосой просмотра операцию сдвига на одну страницу вниз
SCROLL_PAGE_UP | Пользователь выполнил над полосой просмотра операцию сдвига на одну страницувверх
WINDOW_DEICONIFY | Пользователь запросил операцию восстановления нормального размера окна после его минимизации
WINDOW_DESTROY | Пользователь собирается удалить окно
WINDOW_EXPOSE | Окно будет отображено
WINDOW_ICONIFY | Окно будет минимизировано
WINDOW_MOVED | Окно будет перемещено

Если событие связано с клавиатурой (тип события KEY_ACTION или KEY_ACTION_RELEASE), в поле key может находиться одно из следующих значений:

Значение | Клавиша
DOWN | Клавиша перемещения курсора вниз
END | <End>
F1 | <F1>
F2 | <F2>
F3 | <F3>
F4 | <F4>
F5 | <F5>
F6 | <F6>
F7 | <F7>
F8 | <F8>
F9 | <F9>
F10 | <F10>
F11 | <F11>
F12 | <F12>
HOME | <Home>
LEFT | Клавиша перемещения курсора влево
PGDN | <Page Down>
PGUP | <Page Up>
RIGHT | Клавиша перемещения курсора вправо
UP | Клавиша перемещения курсора вверх

Могут быть указаны следующие маски для поля модификаторов modifiers:

Значение маски | Описание
ALT_MASK | Была нажата клавиша <Alt>
META_MASK | Была нажата мета-клавиша (клавиша для ввода диактрических символов)
CTRL_MASK | Была нажата клавиша <Ctrl>
SHIFT_MASK | Была нажата клавиша <Shift>

Ваше приложение может переопределить метод handleEvent и обрабатывать события самостоятельно, однако есть более простой путь. Обработчик этого метода, который используется по умолчанию, вызывает несколько методов, которые более удобны в использовании, в частности, при обработке событий от мыши или клавиатуры.


События от мыши
События
Обработка событий
События от мыши
Аплет LineDraw
Исходный текст
Описание текста

События от мыши

Назад Вперед

В этом разделе мы рассмотрим события, которые возникают в результате того, что пользователь выполняет в окне аплета операции с мышью. Это такие операции, как нажатие и отпускание клавиши мыши, перемещение курсора мыши в окне аплета с нажатой или отпущенной клавишей, перемещение курсора мыши в окно аплета и удаление этого курсора из окна аплета.

Все перечисленные ниже методы должны вернуть значение true, если обработка события выполнена успешно и дальнейшая обработка не требуется. Если же методы вернут значение false, событие будет обработано методом из базового класса, то есть для него будет выполнена обработка, принятая по умолчанию.

Программисты, создававшие приложения для операционной системы Microsoft Windows, могут найти здесь аналогию с вызовом функции DefWindowProc, которая выполняет обработку сообщений, принятую по умолчанию.

Нажатие клавиши мыши

Переопределив метод mouseDown, вы сможете отслеживать нажатия клавиши мыши. Прототип этого метода приведен ниже:

public boolean mouseDown(Event evt, int x, int y);

Через параметр evt методу передается ссылка на объект Event, с помощью которой метод может получить полную информацию о событии.

Анализируя содержимое параметров x и y, приложение может определить координаты курсора на момент возникновения события.

Заметим, что для отслеживания двойного щелчка мыши не предусмотрено никакого отдельного метода. Однако анализируя содержимое поля clickCount переменной evt, вы можете определить кратность щелчка мыши:

if(evt.clickCount > 1)
  // Двойной щелчок
  showStatus("Mouse Double Click");
else
  // Одинарный щелчок
  showStatus("Mouse Down");

Отпускание клавиши мыши

При отпускании клавиши мыши управление получает метод mouseUp:

public boolean mouseUp(Event evt, int x, int y);

Анализируя параметры x и y, вы можете определить координаты точки, в которой пользователь отпустил клавишу мыши.

Перемещение курсора мыши

Когда пользователь перемещает курсор мыши над окном аплета, в процессе перемещения происходит вызов метода mouseMove:

public boolean mouseMove(Event evt, int x, int y);

Через переменные x и y передаются текущие координаты курсора мыши.

Выполнение операции Drag and Drop

Операция Drag and Drop выполняется следующим образом: пользователь нажимает клавишу мыши и, не отпуская ее, начинает перемещать курсор мыши. При этом происходит вызов метода mouseDrag:

public boolean mouseDrag(Event evt, int x, int y);

Через переменные x и y передаются текущие координаты курсора мыши. Метод mouseDrag вызывается даже в том случае, если в процессе перемещения курсор вышел за пределы окна аплета.

Вход курсора мыши в область окна аплета

Метод mouseEnter получает управление, когда курсор мыши в процессе перемещения по экрану попадает в область окна аплета:

public boolean mouseEnter(Event evt, int x, int y);

Вы можете использовать этот метод для активизации аплета, на который указывает курсор мыши.

Выход курсора мыши из области окна аплета

Метод mouseExit вызывается при покидании куросром окна аплета:

public boolean mouseExit(Event evt, int x, int y);

Если пользователь убрал курсор из окна аплета, активизированного методом mouseEnter, то метод mouseExit может переключить аплет в пассивное состояние.


Аплет LineDraw
События
Обработка событий
События от мыши
Аплет LineDraw
Исходный текст
Описание текста

Аплет LineDraw

Назад Вперед

В аплете LineDraw мы показали основные приемы обработки событий, вызываемых мышью. Вы можете рисовать в окне аплета прямые линии, причем возле концов линий отображаются их координаты (рис. 1).

pic01.gif (4730 bytes)

Рис. 1. Окно аплета LineDraw с нарисованными в нем линиями

Для того чтобы нарисовать линию в окне аплета LineDraw, вы должны установить курсор в начальную точку, нажать клавишу мыши и затем, не отпуская ее, переместить курсор в конечную точку. После отпускания клавиши мыши координаты линии будут сохранены аплетом в массиве, после чего произойдет перерисовка окна аплета.

По мере того как вы будете рисовать линии, аплет будет заполнять массив с координатами линий. Каждый раз, когда окно аплета будет перерисовываться, метод paint перерисует все линии заново, пользуясь координатами, сохраненными в массиве.

Для того чтобы стереть содержимое окна аплета, вам достаточно сделать двойной щелчок в его окне. При этом из массива координать линий будут удалены все элементы.


Исходный текст
События
Обработка событий
События от мыши
Аплет LineDraw
Исходный текст
Описание текста

Исходный текст аплета LineDraw

Назад Вперед

Исходный текст аплета LieDrnaw вы найдете в листинге 1.

Листинг 1. Файл LieDrnaw.java

import java.applet.*;
import java.awt.*;
import java.util.*;

public class LineDraw extends Applet
{
  Dimension dmDown;
  Dimension dmUp;
  Dimension dmPrev;
  boolean bDrawing;
  Vector lines;
  public String getAppletInfo()
  {
    return "Name: LineDraw";
  }
  public void init()
  {
    bDrawing = false;
    lines = new Vector();
  }
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension = getSize();
    setBackground(Color.yellow);
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    for (int i=0; i < lines.size(); i++)
    {
      Rectangle p =
        (Rectangle)lines.elementAt(i);
      g.drawLine(p.width, p.height,
        p.x, p.y);
      g.drawString("<" + p.width
        + "," + p.height + ">",
        p.width, p.height);
      g.drawString("<" + p.x + "," +
        p.y+ ">", p.x, p.y);
    }
    bDrawing = false;
  }
  public boolean mouseDown(Event evt,
    int x, int y)
  {
    if(evt.clickCount > 1)
    {
      lines.removeAllElements();
      repaint();
      return true;
    }
    dmDown = new Dimension(x, y);
    dmPrev = new Dimension(x, y);
    bDrawing = false;
    return true;
  }
  public boolean mouseUp(Event evt,
    int x, int y)
  {
    if(bDrawing)
    {
      dmUp = new Dimension(x, y);
      lines.addElement(
        new Rectangle(dmDown.width,
        dmDown.height, x, y));
      repaint();
      bDrawing = false;
    }
    return true;
  }
  public boolean mouseDrag(Event evt,
    int x, int y)
  {
    Graphics g = getGraphics();
    bDrawing = true;
    g.setColor(Color.yellow);
    g.drawLine(dmDown.width, dmDown.height,
      dmPrev.width, dmPrev.height);
    g.setColor(Color.black);
    g.drawLine(dmDown.width,
      dmDown.height, x, y);
    dmPrev = new Dimension(x, y);
    return true;
  }
  public boolean mouseMove(Event evt,
    int x, int y)
  {
    bDrawing = false;
    return true;
  }
}

Исходный текст документа HTML, подготовленного системой JavaWorkshop, представлен в листинге 2.

Листинг 2. Файл LineDraw.tmp.html

<applet name="LineDraw"
  code="LineDraw"
  codebase=
"file:/e:/Sun/Articles/vol5/src/LineDraw"
  width="500"
  height="600"
  align="Top"
  alt="If you had a java-enabled browser,
you would see an applet here.">
</applet>


Описание текста
События
Обработка событий
События от мыши
Аплет LineDraw
Исходный текст
Описание текста

Описание исходного текста

Назад Вперед

В нашем аплете мы будем создавать объект класса Vector, который является массивом с динамически изменяемым размером. Здесь мы будем хранить координаты нарисованных линий.

Класс Vector имеет полное имя java.util.Vector, поэтому мы подключаем соответствующую библиотеку классов:

import java.util.*;

Поля класса LineDraw

В нашем классе мы определили несколько полей, предназначенных для хранения текущих координат рисуемых линий:

Dimension dmDown;
Dimension dmUp;
Dimension dmPrev;
boolean   bDrawing;
Vector    lines;

В переменную dmDown класса Dimension записываются координаты курсора на момент нажатия клавиши мыши. Если пользователь нажал клавишу мыши для того чтобы приступить к рисованию линии, это будет координатами начала линии.

Когда пользователь отпускает клавишу мыши, координаты записываются в переменную dmUp.

В процессе рисования линии метод mouseDrag стирает ранее нарисованную линию и рисует новую. Координаты конца старой линии хранятся в переменной dmPrev.

Переменная bDrawing типа boolean хранит текущее состояние аплета. Когда аплет находится в состоянии рисования линии, в эту переменную записывается значение true, а когда нет - значение false.

И, наконец, переменная lines типа Vector является динамическим массивом, в котором хранятся координаты нарисованных линий.

Метод getAppletInfo

Метод getAppletInfo возвращает название аплета и не имеет никаких особенностей.

Метод init

Метод init сбрасывает признак рисования, записывая в поле bDrawing значение false, а также создает новый динамический массив в виде объекта класса Vector:

public void init()
{
  bDrawing = false;
  lines = new Vector();
}

Метод paint

После изменения цвета фона и рисования рамки метод paint перебирает в цикле все элементы массива lines, рисуя линии:

for(int i=0; i < lines.size(); i++)
{
  Rectangle p =
    (Rectangle)lines.elementAt(i);

  g.drawLine( p.width, p.height, p.x, p.y);

  g.drawString("<" + p.width + ","
    + p.height + ">",
    p.width, p.height);

  g.drawString("<" + p.x + "," +
    p.y+ ">", p.x, p.y);
}

Для объектов класса Vector метод size возвращает количество элементов в массиве, чем мы воспользовались для проверки условия выхода из цикла.

Чтобы извлечь элемент массива по его номеру, мы применили метод elementAt, передав ему через единственный параметр номер извлекаемого элемента.

Так как в массиве хранятся объекты класса Rectangle, перед инициализацией ссылки p мы выполняем явное преобразование типов.

Координаты концов линий рисуются с помощью уже знакомого вам метода drawString.

Перед завершением работы метод paint сбрасывает признак рисования, записывая в поле bDrawing значение false:

bDrawing = false;

Метод mouseDown

В начале своей работы метод mouseDown определяет, был ли сделан одинарный щелчок клавишей мыши, или двойной. Если был сделан двойной щелчок мышью, метод удаляет все элементы из массива list, а затем перерисовывает окно аплета, вызывая метод repaint:

lines.removeAllElements();
repaint();

После перерисовки окно аплета очищается от линий.

Если же был сделан одинарный щелчок клавишей мыши, метод mouseDown сохраняет текущие координаты курсора в переменных dmDown и dmPrev, а затем сбрасывает признак рисования:

dmDown = new Dimension(x, y);
dmPrev = new Dimension(x, y);
bDrawing = false;

Метод mouseUp

Когда пользователь отпускает клавишу мыши, вызывается метод mouseUp. В его задачу входит сохранение текущих координат курсора мыши в поле dmUp, а также добавление нового элемента в массив lines:

dmUp = new Dimension(x, y);
lines.addElement(
  new Rectangle(dmDown.width,
  dmDown.height, x, y));
repaint();

После добавления элемента в массив метод mouseUp инициирует перерисовку окна аплета, вызывая для этого метод repaint.

Заметим, что в качестве координат начала линии мы записываем в элемент массива координаты точки, где в последний раз пользователь нажимал курсор мыши. В качестве координат конца линии используются текущие координаты курсора на момент отпускания клавиши мыши.

Метод mouseDrag

До сих пор наши аплеты выполняли рисование только в методе paint, и так поступают большинство аплетов. Однако наш аплет должен рисовать линии во время перемещения курсора мыши, так как в противном случае пользователю не будет видно, как пройдет рисуемая линия.

Для того чтобы нарисовать что-либо в окне аплета, наобходимо получить контекст отображения. Методу paint этот контекст передается через парметр как объект класса Graphics. Если же вы собираетесь рисовать в другом методе, отличном от paint, необходимо получить контекст отображения, например, так:

Graphics g = getGraphics();

После получения контекста отображения и включения режима рисования (записью в переменную bDrawing значения true) метод mouseDrag стирает линию, которая была нарисована ранее, в процессе предыдущего вызова этого же метода:

g.setColor(Color.yellow);
g.drawLine(dmDown.width, dmDown.height,
   dmPrev.width, dmPrev.height);

Для стирания линии мы рисуем ее на том же месте с использованием цвета, совпадающего с цветом фона.

Далее метод mouseDrag рисует новую линию черного цвета, соединяя точку, в которой была нажата клавиша мыши, с точкой текущего расположения курсора мыши:

g.setColor(Color.black);
g.drawLine(dmDown.width,
  dmDown.height, x, y);

После рисования линии координаты ее конца сохраняются в поле dmPrev для стирания этой линии при следующем вызове метода mouseDrag:

dmPrev = new Dimension(x, y);
return true;

Метод mouseMove

Метод mouseMove не делает ничего, за исключением того, что он отключает режим рисования. Таким образом, простое перемещение курсора мыши над окном аплета не приводит к рисованию линий.


Компоненты
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Компоненты в окне аплета

Назад Вперед

Практически каждое приложение Windows, за исключением самых простейших, имеет такие органы управления, как меню, кнопки, поля редактирования текстовой информации, переключатели с независимой и зависимой фиксацией и списки. Кроме того, приложение Windows может создавать диалоговые панели, содержащие перечисленные выше и другие органы управления.

В окне аплета вы также можете разместить некоторые из перечисленных выше органов управления, а именно:

  • кнопки;
  • переключатели с независимой фиксацией;
  • переключатели с зависимой фиксацией;
  • статические текстовые поля;
  • однострочные и многострочные поля редактирования текста;
  • списки;
  • полосы просмотра

Самый большой и едва ли приятный сюрприз для вас это то, что при размещении перечисленных органов управления в окне аплета вы не можете задать для них точные координаты и размеры. Размещением занимается система управления внешним видом Layout Manager, которая располагает органы управления по-своему. Вы, однако, можете задавать несколько режимов размещения (последовательное, в ячейках таблицы и так далее), но не координаты или размеры. Это сделано для обеспечения независимости приложений Java от платформ, на которых они выполняются.

Органы управления создаются как объекты классов, порожденных от класса Component (рис. 1). Поэтому в дальнейшем мы будем называть органы управления компонентами.

pic01.gif (3954 bytes)

Рис. 1. Взаимосвязь классов органов управления в приложениях Java

Класс Button позволяет создавать стандартные кнопки. Если вам нужна нестандартная кнопка (например, графическая кнопка), вы можете создать ее на базе класса Canvas.

Для создания переключателей с независимой или зависимой фиксацией предназначен класс CheckBox.

С помощью класса Label вы можете создавать в окне аплета текстовые строки, например, надписи для других компонент. Эти строки не редактируются пользователем.

Класс List, как нетрудно догадаться из названия, предназначен для создания списков.

С помощью класса Scrollbar вы можете создавать полосы просмотра, которые используются, в частности, могострочными полями редактирования текста.

Класс TextComponent служит базовым для двух других классов - TextField и TextArea. Первый из них предназначен для создания однострочных редакторов текста, второй - для создания многострочных редкаторов текста.

Для того чтобы понять, как компоненты размещаются на поверхности окна аплета системой Layout Manager, рассмотрим другую взаимосвязь классов Java, показанную на рис. 2.

pic02.gif (3468 bytes)

Рис. 2. Компоненты и контейнеры

Класс Component служит в качестве базового класса для класса Container. Объекты этого класса, которые мы будем называть контейнерами, могут содержать объекты классов Component и Container. Таким образом, внутри контейнеров могут находиться компоненты и другие контейнеры.

Класс Applet, так же как и другие классы, произведенные от класса Container, является контейнером. Это означает, что аплет может содержать в себе компоненты (такие как органы управления) и контейнеры.

Заметим, что класс Applet наследуется от класса Container через класс Panel, в котором определены методы системы Layout Manager. Настраивая соответствующим образом Layout Manager, мы можем менять стратегию размещения компонент внутри окна аплета.

В окне аплета вы можете создать несколько объектов класса Panel (панелей), разделяющих окно на части. Для каждой такой панели можно установить свою стратегию размещения компонент и контейнеров, что позволяет выполнять достаточно сложную компоновку в окне аплета.

Теперь после такого краткого введения в контейнеры и компоненты мы перейдем к описанию методов создания отдельных компонент.


Кнопки
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Кнопки

Назад Вперед

Как мы уже говорили, стандартные кнопки создаются на базе класса Button. Этот класс очень простой, поэтому мы приведем полное его описание:

Класс Button

Конструкторы

В классе Button определены два конструктора, первый из которых позволяет создавать кнопку без надписи, а второй - кнопку с надписью. Обычно используется второй конструктор.

  public Button();
  public Button(String label);

Методы

  • addNotify

Вызов метода createButton

public void addNotify();

Получение надписи на кнопке

  • getLabel
public String getLabel();

Получение строки параметров, отражающей состояние кнопки

  • paramString
protected String paramString();

Установка надписи на кнопке

  • setLabel
public void setLabel(String  label);

Из методов класса Button вы будете использовать чаще всего два - getLabel и setLabel. Первый из них позволяет получить строку надписи на кнопке, а второй - установить новую надпись.

Обычно аплет создает в своем окне кнопки в процессе своей инициализации при обработке метода init, например:

Button btn1;
. . .
public void init()
{
  btn1 = new Button("Button 1");
  add(btn1);
}

Здесь мы создали кнопку с надписью Button 1. Затем мы добавили эту кнопку в контейнер, которым является окно аплета, с помощью метода add.

Обработка событий от кнопки

Для обработки событий, создаваемых кнопками и другими компонентами, вы можете переопределить метод handleEvent. Однако существует и более простой способ.

Этот способ основан на переопределении метода action, который получает управление, когда пользователь совершает какое-либо действие с компонентом. Под действием подразумевается нажатие на кнопку, завершение ввода текстовой строки, выбор элемента из списка, изменение состояния переключателя и так далее.

Прототип метода action представлен ниже:

public boolean action(Event evt, Object obj)
{
  . . .
}

В качестве первого параметра методу передается ссылка на объект класса Event, содержащий всю информацию о событии. Второй параметр представляет собой ссылку на объект, вызвавший появление события.

Как обрабатывать событие в методе action?

Прежде всего необходимо проверить, объект какого типа создал событие. Это можно сделать, например, следующим образом:

if(evt.target instanceof Button)
{
  . . .
  return true;
}
return false;

Здесь мы с помощью оператора instanceof проверяем, является ли объект, вызвавший появление события, объектом класса Button.

Далее, если в окне аплета имеется несколько кнопок, необходимо выполнить ветвление по ссылкам на объекты кнопок, как это показано ниже:

if(evt.target.equals(btn1))
{
  . . .
}
else if(evt.target.equals(btn2))
{
  . . .
}

. . .

else
{
  return false;
}
return true;

Тем из вас, кто создавал приложения Windows на языке программирования С, этот фрагмент кода может напомнить длинный переключатель switch обработки сообщений Windows.


Переключатели
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Переключатели

Назад Вперед

Аплеты Java могут создавать в своем окне переключатели двух типов: с независимой фиксацией и с зависимой фиксацией.

Переключатели с независимой фиксацией имеют прямоугольную форму и, исходя из названия, работают независимо друг от друга. Если такой переключатель находится во включенном состоянии, внутри изображения маленького квадрата появляется галочка, если в выключенном - галочка исчезает.

Обычно переключатели с независимой фиксацией используются для управления независящими друг от друга режимами или параметрами.

Переключатели с зависимой фиксацией имеют круглую форму. В каждый момент времени может быть включен только один такой переключатель из группы переключателей с фиксацией. Аплет может создавать несколько групп переключателей с зависимой фиксацией.

Переключатели с зависимой фиксацией используются для выбора из нескольких взаимоисключающих возможностей, например, для установки одного из нескольких режимов.

Класс Checkbox

Переключатели с независимой и зависимой фиксацией создаются на базе класса Checkbox. Приведем прототипы конструкторов и методов этого класса:

Конструкторы

Создание переключателя с независимой фиксацией без названия

public Checkbox();

Создание переключателя с независимой фиксацией и названием

public Checkbox(String label);

Создание переключателя с зависимой фиксацией и названием

public Checkbox(String label,
  CheckboxGroup group, boolean state);

Методы

  • addNotify

Вызов метода createCheckbox

public void addNotify();
  • getCheckboxGroup

Получение группы, к которой относится данный переключатель с зависимой фиксацией

public CheckboxGroup getCheckboxGroup();
  • getLabel

Получение названия переключателя

public String getLabel();
  • getState

Определение текущего состояния переключателя

public boolean getState();
  • paramString

Получение строки параметров

protected String paramString();
  • setCheckboxGroup

Установка группы, к которой относится данный переключатель с зависимой фиксацией

public void setCheckboxGroup(CheckboxGroup g);
  • setLabel

Установка названия переключателя

public void setLabel(String label);
  • setState

Установка нового состояния переключателя

public void setState(boolean state);

Создание переключателей с независимой фиксацией

Создать переключатель с независимой фиксацией не сложнее, чем создать кнопку:

Checkbox rdbox1;
. . .
public void init()
{
  rdbox1 = new Checkbox("Switch 1");
  add(rdbox1);
}

В этом фрагменте кода мы создаем переключатель chbox1 с названием Switch 1, а затем с помощью метода add добавляем его в контейнер, которым является окно аплета.

Для определения текущего состояния переключателя вы можете использовать метод getState. Если переключатель включен, этот метод возвращает значение true, а если выключен - значение false.

Создание переключателей с зависимой фиксацией

Для каждой группы переключателей с зависимой фиксацией вы должны создать объект класса CheckboxGroup:

Конструктор

public CheckboxGroup();

Методы

Получение ссылки на переключатель, который находится во включенном состоянии

public Checkbox getCurrent();

Установка указанного переключателя в группе во включенное состояние

public void setCurrent(Checkbox box);

Получение строки, которая представляет группу

public String toString();

Ссылка на этот объект указывается при создании отдельных переключателей с зависимой фиксацией, входящих в группу:

CheckboxGroup grModeGroup;
Checkbox rdbox1;
Checkbox rdbox2;
Checkbox rdbox3;
Checkbox rdbox4;
. . .
public void init()
{
  grModeGroup = new CheckboxGroup();

  rdbox1 = new Checkbox("Mode 1",
    grModeGroup, true);
  rdbox2 = new Checkbox("Mode 2",
    grModeGroup, false);
  rdbox3 = new Checkbox("Mode 3",
    grModeGroup, false);
  rdbox4 = new Checkbox("Mode 4",
    grModeGroup, false);

  add(rdbox1);
  add(rdbox2);
  add(rdbox3);
  add(rdbox4);
}

Через первый параметр конструктору Checkbox в этом примере передается название переключателя, через второй - ссылка на группу, а через третий - состояние, в которое должен быть установлен переключатель. Из всех переключателей группы только один может находиться во включенном состоянии.


Списки Choice
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Списки класса Choice

Назад Вперед

На базе класса Choice вы можете создать списки типа Drop Down или, как их еще называют, "выпадающие" списки. Такой список выглядит как текстовое поле высотой в одну строку, справа от которого располагается кнопка (рис. 3).

pic03.gif (1003 bytes)

Рис. 3. Список типа Drop Down, созданный на базе класса Choice

Если нажать на эту кнопку, список раскроется и вы сможете сделать выбор из его элементов (рис. 4).

pic04.gif (1275 bytes)

Рис. 4. Раскрытый список, созданный на базе класса Choice

В списке класса Choice одновременно можно выбрать только один элемент.

Класс Choice

Приведем описание прототипов конструктора и методов класса Choice:

Конструктор

public Choice();

Методы

  • addItem

Добавление элемента в список

public void addItem(String item);
  • addNotify

Вызов метода createChoice

public void addNotify();
  • countItems

Определение количества элементов в списке

public int countItems();
  • getItem

Получение строки списка по номеру соответствующего ему элемента списка

public String getItem(int index);
  • getSelectedIndex

Получение номера текущего выбранного элемента

public int getSelectedIndex();
  • getSelectedItem

Получение строки, соответствующей текущему выбранному элементу списка

public String getSelectedItem();
  • paramString

Получение строки параметров

protected String paramString();
  • select

Выбор в списке элемента по заданному номеру

public void select(int pos);
  • select

Выбор в списке элемента по заданной строке

public void select(String str);

Создание списков

Конструктор класса Choice не имеет параметров. Создание списка с его помощью не вызовет у вас никаких затруднений:

Choice chBackgroundColor;
chBackgroundColor = new Choice();

Для наполнения списка используйте метод addItem. В качестве параметра ему необходимо передать текстовую строку, которая будет связана с добавляемым элементом списка:

chBackgroundColor.addItem("Yellow");

Далее список можно добавить в окно аплета как компонент с помощью метода add:

add(chBackgroundColor);

Заметим, что список можно заполнять до или после добавления в окно аплета.

После наполнения списка по умолчанию выделяется элемент, который был добавлен в список первым. При помощи метода select вы можете выделить любой элемент списка по его номеру или строке, связанной с элементом.

Когд пользователь выбирает новую строку в списке, возникает событие. Обработчик этого события, реализованный, например, переопределением метода action, может получить номер выбранной строки при помощи метода getSelectedIndex. Пример обработки такого события вы найдете в разделе "Приложение ChoiceList".

Если вас интересует не номер выбранного элемента, а строка, связанная с выбранным элементом, воспользуйтесь методом getSelectedItem.

И, наконец, с помощью метода getItem вы можете получить текст строки, связанной с элементом, по номеру элемента.


Списки List
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Списки класса List

Назад Вперед

На базе класса List вы можете сделать список другого типа, который допускает выбор не только одного, но и нескольких элементов. В отличие от списка, созданного на базе класса Choice, список класса List может занимать прямоугольную область, в которой помещаются сразу несколько элементов. Этот список всегда находится в раскрытом состоянии (рис. 5).

pic05.gif (1457 bytes)

Рис. 5. Список класса List, все элементы которого помещаются в окне списка

Если размеры окна списка класса List недостаточны для того чтобы вместить в себя все элементы, в правой части окна списка автоматически создается полоса просмотра, с помощью которой можно пролистать весь список (рис. 6).

pic06.gif (1367 bytes)

Рис. 6. Список класса List с полосой просмотра

Описание класса List

В классе List определено два конструктора и довольно много различных методов. Ниже мы привели краткое описание класса List:

Конструкторы

Конструктор без параметров

public List();

Конструктор, позволяющий указать количество отображаемых строк и флаг одновременного выбора нескольких элементов

public List(int rows,
  boolean multipleSelections);

Методы

  • addItem

Добавление элемента в список

public void addItem(String item);

Добавление элемента в список с указанием номера позиции

public void addItem(String item, int index);
  • addNotify

Вызов метода createList

public void addNotify();
  • allowsMultipleSelections

Переключение списка в режим, при котором возможно выбирать одновременно несколько элементов

public boolean allowsMultipleSelections();
  • clear

Удаление из списка всех элементов

public void clear();
  • countItems

Определение количества элементов в списке

public int countItems();
  • delItem

Удаление элемента из заданной позиции

public void delItem(int position);
  • delItems

Удаление нескольких элементов

public void delItems(int start, int end);
  • deselect

Отмена выделения элемента с заданной позицией

public void deselect(int index);
  • getItem

Получение строки, связанной с элементом, по позиции этого элемента

public String getItem(int index);
  • getRows

Определение количества элементов, которые видны в окне списка

public int getRows();
  • getSelectedIndex

Определение номера выделенного элемента

public int getSelectedIndex();
  • getSelectedIndexes

Определение номеров выделенных элементов

public int[] getSelectedIndexes();
  • getSelectedItem

Получение текстовой строки, связанной с выделенным элементом

public String getSelectedItem();
  • getSelectedItems

Получение ссылки на массив строк, связанных с выделенными элементами

public String[] getSelectedItems();
  • getVisibleIndex

Определение номера элемента массива, который был сделан в последний раз выделенным с помощью метода makeVisible

public int getVisibleIndex();
  • isSelected

Проверка, является ли выделенной строка с заданным номером

public boolean isSelected(int index);
  • makeVisible

Выполняется свертка элементов списка таким образом, чтобы элемент с заданным номером стал видимым

public void makeVisible(int index);

  • minimumSize

Минимальные размеры области, необходимые для отображения списка

public Dimension minimumSize();

Минимальные размеры области, необходимые для отображения списка с заданным количеством строк

public Dimension minimumSize(int rows);
  • paramString

Получение строки параметров

protected String paramString();
  • preferredSize

Предпочтительные размеры области, необходимые для отображения списка

public Dimension preferredSize();

Предпочтительные размеры области, необходимые для отображения списка с заданным количеством строк

public Dimension preferredSize(int rows);

  • removeNotify

Извещение об уничтожении узла

public void removeNotify();
  • replaceItem

Замещение элемента списка с заданным номером

public void replaceItem(String newValue,
  int index);
  • select

Выделение элемента с заданным номером

public void select(int index);
  • setMultipleSelections

Установка или сброс режима одновременного выделения нескольких строк

public void setMultipleSelections(boolean v);

Создание списка класса List

Процесс создания списка класса List несложен:

List chBackgroundColor;
chBackgroundColor = new List(6, false);

При создании списка вы передаете конструктору количество одновременно отображаемых строк и флаг разрешения одновременного выбора нескольких строк. Если значение этого флага равно true, пользователь сможет выбирать из списка одновременно несколько строк, а если false - только одну строку.

Для наполнения списка вы можете использовать уже знакомый вам метод addItem:

chBackgroundColor.addItem("Yellow");
chBackgroundColor.addItem("Green");
chBackgroundColor.addItem("White");

Список класса List добавляется к окну аплета методом add:

add(chBackgroundColor);

Кратко остановимся на нескольких методах класса List.

Если вы разрешили пользователю выбирать из списка одновременно несколько элементов, то для получения ссылки на массив выбранных элементов вам пригодятся методы getSelectedItems и getSelectedIndexes:

public String[] getSelectedItems();
public int[] getSelectedIndexes();

С помощью метода setMultipleSelections вы можете динамически включать или выключать режим одновременного выбора нескольких элементов.

В некоторых случаях вам может пригодиться метод clear, удаляющий все элементы из списка:

public void clear();

Методика использования других методов очевидна из краткого описания класса List, приведенного в нашей статье.

Обработка событий от списка класса List

В отличие от списка класса Choice, для выбора строки (или нескольких строк) из списка класса List, пользователь должен сделать двойной щелчок левой клавишей мыши по выделенному элементу (или элементам, если выделено несколько элементов). При этом событие можно обработать переопределенным методом action, как мы это делали для списка класса Choice.

Однако список класса List создает события не только при двойном щелчке, но и при выделении или отмены выделения элементов, сделанном пользователем одинарным щелчком клавиши мыши. Аплет может перехватывать и обрабатывать такие события, переопределив метод handleEvent.


Поле Label
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Текстовое поле класса Label

Назад Вперед

На базе класса Label вы можете создать в окне аплета однострочное текстовое поле, которое не поддается редактированию. Основное назначение таких полей - подпись других компонент, таких, например, как группы переключателей или списки.

Класс Label

Ниже мы привели краткое описание класса Label:

Поля

Поля класса Label задают способ выравнивания текстового поля

  • CENTER

Центрирование

public final static int CENTER;
  • LEFT

Выравнивание по левой границе

public final static int LEFT;
  • RIGHT

Выравнивание по правой границе

public final static int RIGHT;

Конструкторы

Создание текстового поля без текста

public Label();

Создание текстового поля с заданным текстом

public Label(String label);

Создание текстового поля с заданным текстом и заданным выравниванием

public Label(String label, int alignment);

Методы

  • addNotify

Вызов метода createLabel

public void addNotify();
  • getAlignment

Определение текущего выравнивания текстового поля

public int getAlignment();
  • getText

Получение текста из поля

public String getText();
  • paramString

Получение строки параметров

protected String paramString();
  • setAlignment

Установка выравнивания текстового поля

public void setAlignment(int alignment);
  • setText

Запись текста в поле

public void setText(String label);

Создание поля класса Label

Текстовое поле класса Label создается вызовом соответствующего конструктора. Например, ниже мы создали текстовое поле, указав строку, которую надо в него записать:

Label lbTextLabel;
lbTextLabel =
  new Label("Выберите выравнивание");

С помощью метода add вы можете добавить текстовое поле в окно аплета:

add(lbTextLabel);

Метод setAlignment позволяет при необходимости изменить выравнивание текста. Способ выравнивания необходимо указать через единственный параметр метода:

lbTextLabel.setAlignment(Label.LEFT);

При помощи метода setText вы сможете динамически изменять текст, расположенный в поле класса Label.


Поле TextField
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Текстовое поле класса TextField

Назад Вперед

Для редактирования одной строки текста вы можете создать текстовое поле на базе класса TextField, которое несложно в использовании. Класс TextField создан на базе другого класса с именем TextComponent, поэтому при работе с текстовым полем класса TextField вы можете использовать и методы класса TextComponent.

Класс TextField

Приведем краткое описание класса TextField:

Конструкторы

Создание поля без текста

public TextField();

Создание поля без текста с заданной шириной

public TextField(int cols);

Создание поля и инициализация его текстом

public TextField(String text);

Создание поля заданной ширины и инициализация его текстом

public TextField(String text,
  int cols);

Методы

  • addNotify

Вызов метода createTextField

public void addNotify();
  • echoCharIsSet

Проверка, установлен ли для поля эхо-символ

public boolean echoCharIsSet();
  • getColumns

Определение размера поля

public int getColumns();
  • getEchoChar

Получение текущего эхо-символа

public char getEchoChar();
  • minimumSize

Определение минимальных размеров области для отображения поля

public Dimension minimumSize();

Определение минимальных размеров области для отображения поля заданной ширины

public Dimension minimumSize(int cols);
  • paramString

Получение строки параметров

protected String paramString();
  • preferredSize

Определение оптимальных размеров области для отображения поля

public Dimension preferredSize();

Определение оптимальных размеров области для отображения поля заданной ширины

public Dimension preferredSize(int cols);
  • setEchoCharacter

Установка эхо-символа для отображения в поле

public void setEchoCharacter(char c);

Создание текстового поля класса TextField

При создании текстового поля вы можете выбрать один из четырех конструкторов, соответственно, для создания поля без текста и без указания размера, без текста заданного размера, для создания поля с текстом и для создания поля с текстом указанного размера.

Вот фрагмент кода, в котором создается поле с текстом, имеющее ширину, достаточную для размещения 35 символов:

TextField txt;
txt = new TextField(
  "Введите строку текста", 35);

Созданное поле добавляется в окно аплета методом add.

Большинство самых полезнных методов, необходимых для работы с полем класса TextField, определено в классе TextComponent, краткое описание которого мы привели ниже.

Класс TextComponent

Методы

  • getSelectedText

Получение текста, выделенного пользователем в окне поля

public String getSelectedText();
  • getSelectionEnd

Получение позиции конца выделенной области

public int getSelectionEnd();
  • getSelectionStart

Получение позиции начала выделенной области

public int getSelectionStart();
  • getText

Получение полного текста из поля

public String getText();
  • isEditable

Проверка, возможно ли редактирование текста в поле

public boolean isEditable();
  • paramString

Получение строки параметров

protected String paramString();
  • removeNotify

Удаление извещения

public void removeNotify();
  • select

Выделение заданной области текста

public void select(int selStart,
  int selEnd);
  • selectAll

Выделение всего текста

public void selectAll();
  • setEditable

Включение или выключение возможности редактирования текста

public void setEditable(boolean t);
  • setText

Установка текста в поле

public void setText(String t);

С помощью метода getText вы можете получить весь текст, который имеется в поле. Метод getSelectedText позволяет получить только ту часть текста, которая предварительно была выделена пользователем.

Приложение может выделить любой фрагмент текста или весь текст при помощи методов select и selectAll, соответственно.

Для записи текста в поле приложение может воспользоваться методом setText.

Возможно, для вас будет интересен метод setEditable, позволяющий переключать текстовое поля из режима, при котором редактирование заблокировано, в режим с разрешенным редактированием и обратно.


Поле TextArea
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Многострочное текстовое поле класса TextArea

Назад Вперед

Если вам нужно поле для ввода многострочной информации, обратите внимание на класс TextArea. С его помощью вы можете создать многострочное поле заданной ширины и высоты, снабженное полосами просмотра.

Класс TextArea создан на базе класса TextComponent, рассмотренном нами ранее, поэтому для работы с многострочными полями вы можете использовать методы этого класса. В частности, вам доступен метод, с помощью которого можно получать из онка редактирования не весь текст, а только выделенную пользователем область.

Класс TextArea

Краткое описание класса TextArea мы привели ниже:

Конструкторы

Создание поля без текста и без указания размеров

public TextArea();

Создание поля без текста с указанием размеров

public TextArea(int rows, int cols);

Создание поля с текстом без указания размеров

public TextArea(String text);

Создание поля с текстом и с указанием размеров

public TextArea(String text,
  int rows, int cols);

Методы

  • addNotify

Вызов метода createTextArea

public void addNotify();
  • append

Добавление текста в поле редактирования

public void append(String str);
  • appendText

Добавление текста в поле редактирования. Этот метод устарел. Вы должны использовать вместо него метод append, описанный выше.

public void appendText(String str);
  • getColumns

Определение количества столбцов поля

public int getColumns();
  • getRows

Определение количества строк поля

public int getRows();
  • insertText

Добавление текста в поле редактирования начиная с заданной позиции

public void insertText(String str, int pos);
  • minimumSize

Определение минимальных размеров области для размещения многострочного текстового поля

public Dimension minimumSize();

Определение минимальных размеров области для размещения многострочного текстового поля с заданным количеством строк и столбцов

public Dimension minimumSize(int rows,
   int cols);
  • paramString

Получение строки параметров

protected String paramString();
  • preferredSize

Определение предпочтительных размеров области для размещения многострочного текстового поля

public Dimension preferredSize();

Определение предпочтительных размеров области для размещения многострочного текстового поля с заданным количеством строк и столбцов

public Dimension preferredSize(int rows,
   int cols);
  • replaceText

Замещение блока текста, начиная с первой позиции и до второй позиции

public void replaceText(String str,
   int start, int end);

Создание поля TextArea

Когда вы создаете многострочное текстовое поле редактирования, то можете использовать конструктор, допускающий указание размеров поля в строках и столбцах:

TextArea txt;
txt = new TextArea("Введите строку текста",
 5, 35);

Созданное поле добавляется в окно аплета методом add.

Отметим, что в классе TextArea есть методы для работы с блоками текста (вставка и замена), а также методы, с помощью которых можно определить количество строк и столбцов в поле редактирования.


Аплет FormDemo
Компоненты
Кнопки
Переключатели
Списки Choice
Списки List
Поле Label
Поле TextField
Поле TextArea
Аплет FormDemo

Аплет FormDemo

Назад Вперед

В аплете FormDemo мы покажем приемы работы с компонентами, такими как переключатели, кнопки, текстовые поля и списки.

Мы разместили несколько таких компонент в окне этого аплета (рис. 7) таким образом, что они образуют собой форму. В этой форме вы можете ввести имя и фамилию, выбрать один из трех режимов работы, а также цвет.

pic07sm.gif (1910 bytes) Рис. 7. Окно аплета FormDemo

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

Переключатели First и Second активизируют однострочные текстовые поля редактирования Enter your first name и Enter your second name. После того как пользователь нажмет кнопку Ready, содержимое активных полей, а также состояние переключателей Mode 1, Mode 2 и Mode 3 будет отображено в многострочном поле редактирования. Это поле находится в нижней части окна аплета.

С помощью списка, расположенного справа от переключателя Mode 3, можно задавать цвет фона многострочного поля. Цвет устанавливается сразу после выбора новой строки из этого списка.

К сожалению, при изменении размеров окна аплета находящиеся в нем компоненты изменяют свое расположение. Этот недостаток мы устраним после того, как расскажем вам о системе Layout Manager, с помощью которой вы можете управлять размещением компонент в окне аплета.

Исходный текст аплета FormDemo

Исходный текст аплета FormDemo вы найдете в листинге 1.

Листинг 1. Файл FormDemo.java

import java.applet.Applet;
import java.awt.*;
import java.util.*;
public class FormDemo extends Applet
{
  Button btReady;

  Checkbox chbox1;
  Checkbox chbox2;
  CheckboxGroup grRadio;
  Checkbox rd1;
  Checkbox rd2;
  Checkbox rd3;

  Choice ch1;
  Label lbFirstName;
  Label lbSecondName;
  TextField txtFirstName;
  TextField txtSecondName;
  TextArea  txta;
  public void init()
  {
    chbox1 = new Checkbox("First");
    add(chbox1);
    lbFirstName =
     new Label("Enter your first name:");
    add(lbFirstName);
    txtFirstName = new TextField(" ", 30);
    add(txtFirstName);
    chbox2 = new Checkbox("Second");
    add(chbox2);
    lbSecondName =
      new Label("Enter your second name:");
    add(lbSecondName);
    txtSecondName = new TextField(" ", 30);
    add(txtSecondName);
    grRadio = new CheckboxGroup();
    rd1 = new Checkbox("Mode 1",
      grRadio, true);
    rd2 = new Checkbox("Mode 2",
      grRadio, false);
    rd3 = new Checkbox("Mode 3",
      grRadio, false);
    add(rd1);
    add(rd2);
    add(rd3);
    ch1 = new Choice();
    ch1.addItem("White");
    ch1.addItem("Green");
    ch1.addItem("Yellow");
    add(ch1);
    setBackground(Color.yellow);
    lbFirstName.setBackground(Color.yellow);
    lbSecondName.setBackground(Color.yellow);
    rd1.setBackground(Color.yellow);
    rd2.setBackground(Color.yellow);
    rd3.setBackground(Color.yellow);
    chbox1.setBackground(Color.yellow);
    chbox2.setBackground(Color.yellow);
    txta = new TextArea("", 6, 45);
    add(txta);
    txta.setBackground(Color.white);
    btReady = new Button("Ready");
    add(btReady);
  }
  public String getAppletInfo()
  {
    return "Name: FormDemo";
  }
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension =
      getSize();
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
  }
  public boolean action(Event evt,
    Object obj)
  {
    Button btn;
    String str1, str2;
    if(evt.target instanceof Button)
    {
      if(evt.target.equals(btReady))
      {
        btn = (Button)evt.target;
    str1 = txtFirstName.getText();
    str2 = txtSecondName.getText();
    if(chbox1.getState())
      txta.append(str1);
    if(chbox2.getState())
      txta.append(str2);
    if(rd1.getState())
      txta.append("\nMode 1\n");
    if(rd2.getState())
      txta.append("\nMode 2\n");
    if(rd3.getState())
      txta.append("\nMode 3\n");
      }
      else
      {
    return false;
      }
      return true;
    }
    else if(evt.target instanceof Choice)
    {
      if(evt.target.equals(ch1))
      {
    if(ch1.getSelectedIndex() == 0)
      txta.setBackground(Color.white);
    if(ch1.getSelectedIndex() == 1)
      txta.setBackground(Color.green);
    if(ch1.getSelectedIndex() == 2)
      txta.setBackground(Color.yellow);
      }
    }
    return false;
  }
}

В листинге 2 мы привели исходный текст документа HTML, созданный для нашего аплета системой Java WorkShop.

Листинг 2. Файл FormDemo.tmp.html

<applet
  name="FormDemo"
  code="FormDemo"
  codebase=
"file:/e:/sun/articles/vol6/src/FormDemo"
  width="500"
  height="600"
  align="Top"
  alt="If you had a java-enabled browser,
 you would see an applet here.">
  <hr>If your browser
recognized the applet tag,
you would see an applet here.<hr>
</applet>

Описание исходного текста

Приведем краткое описание полей и методов, определенных в аплете FormDemo.

Поля главного класса

В главном классе нашего аплета мы определили несколько полей.

Поле btReady хранит ссылку на кнопку с надписью Ready:

Button btReady;

В полях chbox1 и chbox2 записаны ссылки на переключатели с независимой фиксацией, которые используются для активизации однострочных текстовых полей:

Checkbox chbox1;
Checkbox chbox2;

Поле grRadio хранит ссылку на группу переключателей с зависимой фиксацией, определяющих режимы работы Mode 1, Mode 2 и Mode 3:

CheckboxGroup grRadio;

Ссылки на эти переключатели находятся в следующих трех полях:

Checkbox rd1;
Checkbox rd2;
Checkbox rd3;

В поле ch1 хранится ссылка на список, предназначенный для выбора цвета:

Choice ch1;

Слева от однострочных полей редактирования в нашем окне имеются подписи, реализованные как объекты класса Label. Ссылки на эти объекты находятся в полях lbFirstName и lbSecondName:

Label lbFirstName;
Label lbSecondName;

Ссылки на однострочные поля редактирования записаны в поля с именами txtFirstName и txtSecondName:

TextField txtFirstName;
TextField txtSecondName;

И, наконец, ссылка на многострочное текстовое поле хранится в поле с именем txta:

TextArea  txta;

Метод init

Метод init занимается созданием компонент и добавлением их в окно алпета. Кроме того, этот метод изменяет цвет фона окна аплета и окон добавляемых компонент.

Прежде всего метод init создает два переключателя с независимой фиксацией, два объекта класса Label и два однострочных поля редактирования текста:

chbox1 = new Checkbox("First");
add(chbox1);
lbFirstName =
   new Label("Enter your first name:");
add(lbFirstName);
txtFirstName = new TextField(" ", 30);
add(txtFirstName);
chbox2 = new Checkbox("Second");
add(chbox2);
lbSecondName =
  new Label("Enter your second name:");
add(lbSecondName);
txtSecondName = new TextField(" ", 30);
add(txtSecondName);

Поля создаются при помощи конструкторов, а добавляются в окно аплета методом add. Согласно схемы расположения компонент, установленой по умолчанию, добавляемые компоненты размещаются сверху вниз и слева направо.

Для группы переключателей с зависимой фиксацией мы создаем объект класса CheckboxGroup:

grRadio = new CheckboxGroup();

Ссылка на этот объект затем передается в качестве второго параметра конструкторам, создающим переключатели:

rd1 = new Checkbox("Mode 1",
    grRadio, true);
rd2 = new Checkbox("Mode 2",
    grRadio, false);
rd3 = new Checkbox("Mode 3",
    grRadio, false);

Переключатели добавляются в окно аплета при помощи метода add:

add(rd1);
add(rd2);
add(rd3);

Список цветов создается как объект класса Choice:

ch1 = new Choice();

После создания списка мы добавляем в него три элемента, вызывая для этого метод addItem:

ch1.addItem("White");
ch1.addItem("Green");
ch1.addItem("Yellow");

Вслед за этим мы добавляем сформированный список в окно аплета:

add(ch1);

Для установки цвета фона мы вызываем метод setBackground без указания объекта:

setBackground(Color.yellow);

В этом случае метод вызывается для текущего объекта, то есть для нашего аплета. Чтобы установить цвет фона в окнах компонент, мы вызываем метод setBackground для соответствующих объектов, как это показано ниже:

lbFirstName.setBackground(Color.yellow);
lbSecondName.setBackground(Color.yellow);
rd1.setBackground(Color.yellow);
rd2.setBackground(Color.yellow);
rd3.setBackground(Color.yellow);
chbox1.setBackground(Color.yellow);
chbox2.setBackground(Color.yellow);

Многострочное текстовое поле создается как объект класса TextArea. В нем 6 строк и 45 столбцов:

txta = new TextArea("", 6, 45);
add(txta);

Первоначальный цвет фона многострочного текстового поля устанавливается тем же способом, чтомы использовали для других компонент:

txta.setBackground(Color.white);

Этот цвет в дальнейшем будет изменяться обработчиком событий, создаваемых списком цветов.

И, наконец, последнее что делает метод init перед тем как вернуть управление, - создает кнопку с надписью Ready и добавляет ее в окно аплета:

btReady = new Button("Ready");
add(btReady);

Метод action

В методе action мы определили рабочие поля btn, str1 и str2:

Button btn;
String str1, str2;

В начале своей работы метод action определяет, какой компонент вызвал событие. Для этого анализируется поле evt.target:

if(evt.target instanceof Button)
{
  . . .
  return true;
}
else if(evt.target instanceof Choice)
{
  . . .
  return true;
}
return false;

Наш метод action обрабатывает события, вызываемые объектами классов Button и Choice. Если событие вызвано компонентом, относящимся к какому-либо другому классу, метод возвращает значение false. Этим он сигнализирует, что обработка события не выполнялась.

В случае успешной обработки события метод action возвращает значение true.

Если событие вызвано кнопкой, наш метод action проверяет, какой именно. Обработка выполняется только в том случае, если через поле evt.target передается ссылка на кнопку btReady:

if(evt.target.equals(btReady))
{
  . . .
}
else
{
  return false;
}
  return true;

В противном случае метод action возвращает значение false, отказываясь от обработки события.

Что делает обработчик события, создаваемого кнопкой?

Прежде всего, он сохраняет ссылку на кнопку в рабочей переменной (просто для того чтобы показать, как это делается):

btn = (Button)evt.target;

Далее наш обработчик события извлекает текстовые строки из однострочных текстовых полей, вызывая для этого метод getText. Эти строки записываются в рабочие переменные str1 и str2:

str1 = txtFirstName.getText();
str2 = txtSecondName.getText();

Затемметод action проверяет состояние переключателей с независимой фиксацией chbox1 и chbox2. Если они включены, содержимое соответствующих временных переменных добавляется в многострочное текстовое поле txta:

if(chbox1.getState())
   txta.append(str1);
if(chbox2.getState())
   txta.append(str2);

Для добавления мы вызываем метод append.

Аналогичным образом преверяется состояние переключателей с зависимой фиксацией:

if(rd1.getState())
  txta.append("\nMode 1\n");
if(rd2.getState())
  txta.append("\nMode 2\n");
if(rd3.getState())
  txta.append("\nMode 3\n");

Если событие вызвано списокм цветов ch1, то метод action определяет, какая строка списка стала выделенной и устанавливает в многострочном поле редактирования соответствующий цвет фона. Для определения выделенной строки применяется метод getSelectedIndex:

if(evt.target.equals(ch1))
{
  if(ch1.getSelectedIndex() == 0)
    txta.setBackground(Color.white);
  if(ch1.getSelectedIndex() == 1)
    txta.setBackground(Color.green);
  if(ch1.getSelectedIndex() == 2)
    txta.setBackground(Color.yellow);
}

Работу остальных методов приложения FormDemo вы сможете разобрать самостоятельно.


Рис. 7. Окно аплета FormDemo

Для возврата сделайте щелчок мышью по рисунку

Рис. 7. Окно аплета FormDemo


Работа с системой Layout Manager
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Работа с системой Layout Manager

Назад Вперед

В предыдущей статье мы рассказали вам о том, как создавать компоненты и размещать их в контейнере. Однако предложенный способ размещения компонент в окне контейнера едва ли можно назвать удобным, так как заранее трудно предугадать, на каком месте окажется тот или иной орган управления.

К счастью, имеются способы, позволяющие контролировать размещение отдельных компонент в окне контейнера. И хотя эти способы не позволяют задавать конкретные координаты и размеры органов управления, использовнные схемы размещения компонент будут правильно работать на любой аппаратной платформе (не забывайте, что Java создавалась как средство разработки приложений, способных выполняться на любой платформе).

В чем трудность создания пользовательского интерфейса для мультиплатформных систем?

В том, что разработчик приложения никогда не знает характеристики устройства отображения, установленные у пользователя. Он, в частности, не может заранее знать разрешение монитора, размер системного шрифта и другие характеристики, необходимые для компоновки диалоговых панелей в терминах абсолютных координат.

Средства пользовательского интерфейса AWT способны динамически измнять размеры компонент, подгоняя их "по месту" в системе пользователя. В результате значительно повышается вероятность того что внешний вид диалоговой панели, в каком она предстанет перед пользователем, будет похож на то, что ожидал разработчик.


Режимы системы Layout Manager
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Режимы системы Layout Manager

Назад Вперед

Прежде чем мы рассмотрим различные режимы компоновки системы Layout Manager, вспомним, как происходит наследование класса Applet (рис. 1).

pic01.gif (2563 bytes)

Рис. 1. Наследование класса Applet

Класс Applet наследуется от класса Panel, который, в свою очередь, наследуется от класса Container и Component. Класс Container пользуется интерфейсом LayoutManager, что позволяет выбирать для контейнеров один из нескольких режимов размещения компонент в окне контейнера.

Что же касается класса Panel, то для него по умолчанию выбирается режим размещения компонент с названием Flow Layout. Разумеется, вы можете выбрать другой режим размещения, указав его явным образом.

Ниже мы перечислили все возможные режимы системы Layout Manager:

Режим размещения компонент | Описание
FlowLayout | Компоненты заполняют окно контейнера "потоком" по мере их добавления методом add. Они размещаются слева направо и сверху вниз
GridLayout | Компоненты размещаются в виде таблицы по мере добавления слева направо и сверху вниз. Для этой таблицы можно указать количество столбцов и строк
GridBagLayout | Аналогично предыдущему, однако при добавлении компонент в таблицу можно указать координаты ячейки, в которую помещается компонента
BorderLayout | При размещении компоненты указывается одно из нескольких направлений: юг, север, запад, восток, центр. Направление определяется относительно центра окна контейнера
CardLayout | Размещение компонент друг над другом в одном окне. Этот режим позволяет организовать набор диалоговых панелей в виде блокнота

Каждому режиму соответсвует одноименный класс, методы и конструкторы которого позволяют выбирать различные компоновки.

Далее на примере конкретного приложения мы рассмотрим использование перечисленных выше режимов системы Layout Manager.


Режимы FlowLayout
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Режим FlowLayout

Назад Вперед

В этом режиме мы добавляли компоненты во всех примерах аплетов, приведенных ранее, так как по умолчанию для аплетов используется именно режим FlowLayout.

Класс FlowLayout

Ниже мы привели краткое описание класса FlowLayout:

Поля

Следующие три поля задают способы выравнивания:

  • CENTER

Центрирование

public final static int CENTER;
  • LEFT

По левой границе

public final static int LEFT;
  • RIGHT

По правой границе

public final static int RIGHT;

Конструкторы

Без указания выравнивания и зазора между компонентами

public FlowLayout();

С указанием выравнивания

public FlowLayout(int align);

С указанием выравнивания и зазора между компонентами по вертикали и горизонтали

public FlowLayout(int align,
  int hgap, int vgap);

Обычно приложения не вызывают методы класса FlowLayout, устанавливая варианты компоновки при помощи конструкторов.

Первый конструктор класса FlowLayout не имеет параметров. Он устанавливает по умолчанию режим центрирования компонент и зазор между компонентами по вертикали и горизонтали, равный 5 пикселам. Именно этот режим и использовался раньше во всех наших аплетах, так как именно он применяется по умолчанию объектами класса Panel, от которого наследуется класс Applet.

С помощью второго конструктора вы можете выбрать режим размещения с заданным выравниванием компонент в окне контейнера по горизонтали. В качестве параметров этому конструктору необходимо передавать значения FlowLayout.LEFT, FlowLayout.RIGHT, или FlowLayout.CENTER. Зазор между компонентами будет при этом равен по умолчанию 5 пикселам.

И, наконец, третий конструктор допускает раздельное указание режима выравнивания, а также зазоров между компонентами по вертикали и горизонтали в пикселах.

Методы

  • addLayoutComponent

Не используется

public void addLayoutComponent(
  String name, Component comp);
  • layoutContainer

Предназначен для того чтобы компоненты могли установить для себя предпочтительный размер

public void layoutContainer(
  Container target);
  • minimumLayoutSize

Определение минимального размера окна контейнера, необходимого для размещения всех компонент

public Dimension minimumLayoutSize(
  Container target);
  • preferredLayoutSize

Определение предпочтительного размера окна контейнера, необходимого для размещения всех компонент

public Dimension preferredLayoutSize(
  Container target);
  • removeLayoutComponent

Удаление компоненты из контейнера

public void removeLayoutComponent(
  Component comp);
  • toString

Получение строки названия метода компоновки

public String toString();


Режимы GridLayout
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Режим GridLayout

Назад Вперед

В режиме GridLayout компоненты размещаются в ячейках таблицы, параметры которой можно задать с помощью конструкторов класса GridLayout.

При размещении компонент внутри ячеек таблицы все они получают одинаковые размеры. Если один из параметров, задающих размерность таблицы, равен нулю, это означает, что соответствующий столбец или строка может содержать любое количество элементов.

Заметим, что оба параметра rows и cols не могут быть равны нулю одновременно.

Приведем описание конструкторов класса GridLayout.

Конструкторы

Создание таблицы с заданным количеством строк и столбцов

public GridLayout(
  int rows, int cols);

Создание таблицы с заданным количеством строк и столбцов и с заданным зазором между компонентами

public GridLayout(int rows,
  int cols, int hgap, int vgap);

Методы

Методы класса GridLayout используются редко, поэтому мы их только перечислим.

public void addLayoutComponent(
  String name,Component comp);
public void layoutContainer(
  Container target);
public Dimension minimumLayoutSize(
  Container target);
public Dimension preferredLayoutSize(
  Container target);
public void removeLayoutComponent(
  Component comp);
public String toString();


Режимы BorderLayout
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Режим BorderLayout

Назад Вперед

При использовании режима BorderLayout окно контейнера разделяется на рамку и центральную часть. При размещении компонент указывается направление от центра окна, в котором слудует размещать компоненты.

Конструкторы класса BorderLayout

Ниже приведено краткое описание конструкторов класса BorderLayout.

public BorderLayout();
public BorderLayout(int hgap, int vgap);

Эти конструкторы предназначены для создания схемы размещения, без зазора между компонентами и с зазором заданной величины,соответственно.

Методы класса BorderLayout

Перечислим также методы классаBorderLayout:

public void  addLayoutComponent(
  String name, Component comp);
public void layoutContainer(
  Container target);
public Dimension minimumLayoutSize(
  Container target);
public Dimension preferredLayoutSize(
  Container target);
public void removeLayoutComponent(
  Component comp);
public String toString();

Применение класса BorderLayout

Добавляя компоненты к контейнеру, вы должны использовать метод add с двумя параметрами, первый из которых указывает направление размещения, а второй - ссылку на добавляемый объект:

add("North",  btn1);
add("East",   btn2);
add("West",   btn3);
add("South",  btn4);
add("Center", btn5);


Режимы CardLayout
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Режим CardLayout

Назад Вперед

Режим CardLayout предназначен для создания набора диалоговых панелей, которые можно показывать по очереди в одном окне прямоугольной формы. Обычно для управления процессом перебора диалоговых панелей в режиме CardLayout используются отдельные органы управления, расположенные в другой панели или даже в другом аплете на той же самой странице сервера Web.

Класс CardLayout содержит два конструктора и несколько методов.

Конструкторы класса CardLayout

Режим без зазоров

public CardLayout();

Режим с зазорами по вертикали и горизонтали между компонентами и окном контейнера

public CardLayout(int hgap, int vgap);

Методы класса CardLayout

  • addLayoutComponent

Добавление компоненты с указанием имени

public void addLayoutComponent(
  String name, Component comp);
  • first

Отображение первой страницы блокнота

public void first(Container target);
  • last

Отображение последней страницы блокнота

public void last(Container target);
  • next

Отображение следующей страницы блокнота

public void next(Container target);
  • previous

Отображение предыдущей страницы блокнота

public void previous(Container target);
  • layoutContainer

Выполнение размещения компонент

public void layoutContainer(
  Container target);
  • minimumLayoutSize

Определение минимальных размеров окна, необходимых для размещения компонент

public Dimension minimumLayoutSize(
  Container target);
  • preferredLayoutSize

Определение предпочтительных размеров окна, необходимых для размещения компонент

public Dimension preferredLayoutSize(
  Container target);
  • removeLayoutComponent

Удаление заданной компоненты

public void removeLayoutComponent(
  Component comp);
  • show

Отображение произвольной страницы блокнота по ее имени

public void show(
  Container target, String name);
  • toString

Получение текстовой строки названия режима размещения

public String toString();

Использование режима размещения CardLayout

Как пользоваться режимом размещения CardLayout?

Обычно в окне аплета создается две панели, одна из которых предназначена для показа страниц блокнота в режиме размещения CardLayout, а вторая содержит органы управления перелистыванием страниц, например, кнопки.

Такие методы, как first, last, next и previous позволяют отображать, соответственно, первую, последнюю, следующую и предыдущую страницу блокнота. Если вызвать метод next при отображении последней страницы, в окне появится первая страница. Аналогично, при вызове метода previous для первой страницы блокнота вы увидите последнюю страницу.

А как отобразить произвольную страницу, не перебирая их по одной методами next и previous?

Для этого существует метод show. Учтите, что этот метод позволяет отображать только такие страницы, при добавлении которых методом add было указано имя, например:

pCardPanel.add("BackgroundColor",
  pBackgroundColor);
pCardPanel.add("ForegroundColor",
  pForegroundColor);
pCardPanel.add("Font", pFont);

Здесь в панель pCardPanel добавляются панели pBackgroundColor, pForegroundColor и pFont, имеющие имена, соответственно, "BackgroundColor", "ForegroundColor" и "Font".


Режимы GridBagLayout
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Режим GridBagLayout

Назад Вперед

Режим GridBagLayout намного сложнее только что описанного режима GridLayout. Он позволяет размещать компоненты разного размера в таблице, задавая при этом для отдельных компонент размеры отступов и количество занимаемых ячеек.

Сейчас мы не будем рассматривать этот режим, так как сходные результаты могут быть достигнуты другими, менее сложными способами. Например, вы можете создать в контейнере несколько панелей, использовав внутри каждой свой метод размещения компонент.

Если вы создаете аплеты для размещения в документах HTML, никто не заставляет вас ограничиваться только одним аплетом для одного документа HTML - вы можете разместить там произвольное количество аплетов, организовав взаимодействие с одной стороны, между отдельными аплетами, а с другой - между аплетами и расширениями сервера Web.

В интегрированной системе разработки приложений Java WorkShop версии 2.0 имеется встроенная система визуального проектирования пользовательского интерфейса, в результате работы которой создаются исходные тексты классов. Размещение органов управления при этом выполняется интерактивными средствами.


Аплет FormLayout
Работа с системой Layout Manager
Режимы системы Layout Manager
Режимы FlowLayout
Режимы GridLayout
Режимы BorderLayout
Режимы CardLayout
Режимы GridBagLayout
Аплет FormLayout

Аплет FormLayout

Назад Вперед

В окне аплета FormLayout (рис. 2) мы расположили те же самые органы управления, которые были использованы в предыдущем аплете FormDemo. Однако для указания способа размещения компонент мы выполнили настройку системы Layout Manager, выбрав режим GridLayout.

pic02sm.gif (2024 bytes) Рис. 2. Окно аплета FormLayout

Для того чтобы увидеть рисунок в увеличенном виде, сделайте щелчок мышью по изображению

И хотя пока еще внешний вид нашей формы оставляет желать лучшего, расположение отдельных компонент не изменяется при изменении размеров окна аплета.

Проблема заключается в том, что в режиме GridLayout не удается управлять размерами компонент. Для устранения этого недостатка следует использовать режим GridBagLayout. Так как этот режим сложен для использования без визуального проектирования, мы отложим дальнейшее совершенстовование нашей формы до тех пор, пока не займемся изучением соответствующих средств Java WorkShop.

Исходный текст аплета FormLayout

Исходный текст аплета FormLayout практически повторяет исходный текст аплета FormDemo, рассмотренный в нашей предыдущей статье. Единственное отличие заключается в том, что в методе init мы выполнили настройку системы Layout Manager, установив режим GridLayout:

public void init()
{
  setLayout(new GridLayout(4, 3));
  . . .
}

Здесь для размещения компонент в окне аплета создается таблица из четырех строк и трех столбцов.

Полный исходный текст аплета FormLayout вы найдете в листинге 1.

Листинг 1. Файл FormLayout.java

import java.applet.Applet;
import java.awt.*;
import java.util.*;
public class FormLayout extends Applet
{
  Button btReady;
  Checkbox chbox1;
  Checkbox chbox2;
  CheckboxGroup grRadio;
  Checkbox rd1;
  Checkbox rd2;
  Checkbox rd3;
  Choice ch1;
  Label lbFirstName;
  Label lbSecondName;
  TextField txtFirstName;
  TextField txtSecondName;
  TextArea  txta;
  public void init()
  {
    setLayout(new GridLayout(4, 3));
    chbox1 = new Checkbox("First");
    add(chbox1);
    lbFirstName = new Label(
      "Enter your first name:");
    add(lbFirstName);
    txtFirstName = new TextField(" ", 30);
    add(txtFirstName);
    chbox2 = new Checkbox("Second");
    add(chbox2);
    lbSecondName = new Label(
     "Enter your second name:");
    add(lbSecondName);
    txtSecondName = new TextField(" ", 30);
    add(txtSecondName);
    grRadio = new CheckboxGroup();
    rd1 = new Checkbox("Mode 1",
      grRadio, true);
    rd2 = new Checkbox("Mode 2",
      grRadio, false);
    rd3 = new Checkbox("Mode 3",
      grRadio, false);
    add(rd1);
    add(rd2);
    add(rd3);
    ch1 = new Choice();
    ch1.addItem("White");
    ch1.addItem("Green");
    ch1.addItem("Yellow");
    add(ch1);
    setBackground(Color.yellow);
    lbFirstName.setBackground(
      Color.yellow);
    lbSecondName.setBackground(
      Color.yellow);
    rd1.setBackground(Color.yellow);
    rd2.setBackground(Color.yellow);
    rd3.setBackground(Color.yellow);
    chbox1.setBackground(Color.yellow);
    chbox2.setBackground(Color.yellow);
    txta = new TextArea("", 6, 45);
    add(txta);
    txta.setBackground(Color.white);
    btReady = new Button("Ready");
    add(btReady);
  }
  public String getAppletInfo()
  {
    return "Name: FormDemo";
  }
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension =
      getSize();
    g.setColor(Color.black);
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
  }
  public boolean action(Event evt,
    Object obj)
  {
    Button btn;
    String str1, str2;
    if(evt.target instanceof Button)
    {
      if(evt.target.equals(btReady))
      {
        btn = (Button)evt.target;
    str1 = txtFirstName.getText();
    str2 = txtSecondName.getText();
    if(chbox1.getState())
      txta.append(str1);
    if(chbox2.getState())
      txta.append(str2);
    if(rd1.getState())
      txta.append("\nMode 1\n");
    if(rd2.getState())
      txta.append("\nMode 2\n");
    if(rd3.getState())
      txta.append("\nMode 3\n");
      }
      else
      {
    return false;
      }
      return true;
    }
    else if(evt.target instanceof Choice)
    {
      if(evt.target.equals(ch1))
      {
    if(ch1.getSelectedIndex() == 0)
      txta.setBackground(Color.white);
    if(ch1.getSelectedIndex() == 1)
      txta.setBackground(Color.green);
    if(ch1.getSelectedIndex() == 2)
      txta.setBackground(Color.yellow);
      }
    }
    return false;
  }
}

Исходный текст документа HTML, созданный для нашего аплета системой Java WorkShop, представлен в листинге 2.

Листинг 2. Файл FormLayout.tmp.html

<applet
  name="FormLayout"
  code="FormLayout"
  codebase=
  "file:/e:/sun/articles/vol7/src/FormLayout"
  width="500"
  height="600"
  align="Top"
  alt="If you had a java-enabled browser,
 you would see an applet here.">
</applet>


Рис. 2. Окно аплета FormLayout

Для возврата сделайте щелчок мышью по рисунку

Рис. 2. Окно аплета FormLayout


Работа с панелями
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Работа с панелями

Назад Вперед

Панели, создаваемые на базе класса Panel, являются мощным средством организации диалогового интерфейса. Так как класс Panel произошел от класса Container, панель может содержать компоненты и другие панели. Для каждой панели можно определить режим размещения компонент, что позволяет создавать достаточно сложный пользовательский интерфейс.

В окне аплета вы можете создать несколько панелей, разделяющих его на части. В свою очередь, пространство, занимаемое панелями, также может быть разделено с использованием одного из описанных выше режимов размещения (рис. 1).

pic01.gif (3017 bytes)

Рис. 1. Размещение нескольких панелей в окне аплета

Отдельные панели могут содержать в себе такие компоненты, как кнопки, переключатели, списки, текстовые поля и так далее.


Создание панелей
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Создание панелей

Назад Вперед

Панель создается очень просто. Прежде всего необходимо выбрать для окна аплета схему размещения компонент, соответствующую требуему расположению панелей. Например, для создания в окне аплета двух панелей, разделяющих его по горизонтали, следует выбрать режим GridLayout:

setLayout(new GridLayout(2, 1));

Панели будут размещаться в ячейках таблицы, состоящей из одного столбца и двух строк.

Далее нужно создать объекты класса Panel:

Panel pTopPanel;
pTopPanel = new Panel();
Panel pBottomPanel;
pBottomPanel = new Panel();

Ссылка на панель, которая будет располагаться сверху, записывается в переменную pTopPanel, а на ту, что будет располагаться снизу - в переменную pBottomPanel.


Добавление панелей
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Добавление панелей

Назад Вперед

Создав панели, вы можете добавить их в окно аплета, вызвав метод add, как это показано ниже:

add(pTopPanel);
add(pBottomPanel);

Заметим, что вы можете добавлять панели в панели, указывая, для какой панели нужно вызывать метод add:

Panel pLeft;
Panel pRight;
pLeft  = new Panel();
pRight = new Panel();
pTopPanel.setLayout(new GridLayout(1, 2));
pTopPanel.add(pLeft);
pTopPanel.add(pRight);

Здесь мы создали две панели pLeft и pRight, которые по нашему замыслу должны разделить пространство панели pTopPanel на две части по вертикали. Для обеспечения вертикального размещения панелей pLeft и pRight в панели pTopPanel мы вызвали для панели pTopPanel метод setLayout. При этом мы указали, что компоненты, добавляемые в эту панель, должны размещаться в таблице, состоящей из односй строки и двух столбцов.

Затем панели pLeft и pRight были добавлены в панель pTopPanel методом add.


Добавление компонент
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Добавление компонент в панели

Назад Вперед

Для добавления компонент в панель вы должны указать, для какой панели вызывается метод add, например:

Botton btn1;
Botton btn2;
btn1 = new Button();
btn2 = new Button();
pBottomPanel.add(btn1);
pBottomPanel.add(btn2);


Рисование в панели
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Рисование в окне панели

Назад Вперед

Как вы знаете, для того чтобы что-нибудь нарисовать, необходимо вначале получить контекст отображения. Методу paint передается контекст отображения, связанный с окном аплета. Если в окне имеются панели, то для рисования внутри них необходимо получить контекст отображения окон панелей.

Проще всего это сделать с помощью метода getGraphics, вызвав его для объекта класса Panel:

Graphics gpDraw;
gpDraw = pDraw.getGraphics();

Здесь в переменную gpDraw мы записали ссылку на контекст отображения для панели pDraw.

Получив контекст отображения, можно приступить к рисованию. Вот, например, как можно нарисовать вокруг панели тонкую рамку:

Dimension dimAppWndDimension = pDraw.size();
gpDraw.drawRect(0, 0,
  dimAppWndDimension.width  - 1,
  dimAppWndDimension.height - 1);

В этом фрагменте кода мы вначале определили размеры панели, вызвав для нее метод size, а затем при помощи метода drawRect, вызванного для контекста отображения gpDraw, нарисовали рамку.

Для установки шрифта и рисования текста в окне панели вы также должны указывать ссылку на контекст отображения вашей панели:

gpDraw.setFont(new Font("Courier",
  Font.PLAIN, 12));
gpDraw.drawString(
  "Текст внутри окна панели", 10, 50);

Другой способ основан на создании собственного класса на базе класса Panel и переопределения в этом классе метода paint.


Класс на базе Panel
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Создание нового класса на базе класса Panel

Назад Вперед

Если ваш аплет создает много панелей, техника рисования в окнах этих панелей, описанная выше, может привести к усложнению исходного текста приложения. Так как рисование в окнах панелей выполняется в методе paint класса аплета, вам придется получать контекст отображения для каждой панели.

Намного проще создать несколько дочерних классов от класса Panel, переопределив в каждом из них метод paint. В этом случае для каждой панели вы можете создать свой метода paint, которому будет автоматически передаваться контекст отображения, связанный с окном соответствующей панели.

В аплете Options, который мы рассмотрим ниже, использована именно такая методика работы с панелями.


Аплет Options
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Аплет Options

Назад Вперед

Аплет Options демонстрирует методики работы с панелями, а также с различными режимами системы Layout Manager.

В окне аплета Options мы создали три панели (рис. 2).

pic02.gif (4687 bytes)

Рис. 2. Окно аплета Options

В верхней панели отображается текстовая строка First panel. Цвет и шрифт этой строки, а также цвет фона можно задавать при помощи второй панели, расположенной в центре окна нашего аплета.

Вторая панель представляет собой блокнот, на страницах которого находятся списки цвета фона, текста и шрифтов. С помощью кнопок нижней панели вы можете перелистывать страницы этого блокнота. На рис. 3 и 4 мы показали страницы, предназначенные для выбора цвета фона и цвета текста, соответственно.

pic03.gif (4762 bytes)

Рис. 3. Выбор цвета фона

pic04.gif (4864 bytes)

Рис. 4. Выбор цвета текста

Нажимая кнопки Background Color, Foreground Color и Set Font, вы можете отображать нужные вам страницы блокнота. С помощью кнопок Next и Prev можно перебирать страницы блокнота в прямом или обратном направлении, соответственно.


Исходный текст
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Исходный текст аплета Options

Назад Вперед

Исходный текст аплета Options представлен в листинге 1.

Листинг 1. Файл Options.java

import java.applet.*;
import java.awt.*;
public class Options extends Applet
{
  FirstPanel pPanel1;
  CardPanel pCard;
  ControlPanel pControl;
  public String getAppletInfo()
  {
    return "Name: Options";
  }
  public void init()
  {
    setLayout(new GridLayout(3, 1));
    pPanel1 = new FirstPanel();
    add(pPanel1);
    pCard = new CardPanel(pPanel1);
    add(pCard);
    pControl = new ControlPanel(pCard);
    add(pControl);
    pPanel1.setBackground(Color.yellow);
    pPanel1.setForeground(Color.black);
    repaint();
  }
}
class FirstPanel extends Panel
{
  String szFontName = "TimesRoman";
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension = getSize();
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    g.setFont(new Font(szFontName,
      Font.PLAIN, 24));
    g.drawString("First panel", 10, 50);
    super.paint(g);
  }
}
class CardPanel extends Panel
{
  Panel pBgColor;
  Panel pFgColor;
  Panel pFont;
  Panel pControlled;
  Choice chBgColor;
  Choice chFgColor;
  Choice chFont;
  Label lbBgColor;
  Label lbFgColor;
  Label lbFont;
  public CardPanel(Panel pControlledPanel)
  {
    pControlled = pControlledPanel;
    setLayout(new CardLayout(5, 5));
    pBgColor = new Panel();
    pFgColor = new Panel();
    pFont    = new Panel();
    add("BgColor", pBgColor);
    add("FgColor", pFgColor);
    add("Font", pFont);
    chBgColor = new Choice();
    chFgColor = new Choice();
    chFont    = new Choice();
    chBgColor.add("Yellow");
    chBgColor.add("Green");
    chBgColor.add("White");
    chFgColor.add("Black");
    chFgColor.add("Red");
    chFgColor.add("Green");
    chFont.add("TimesRoman");
    chFont.add("Helvetica");
    chFont.add("Courier");
    lbBgColor = new Label("Background color");
    lbFgColor = new Label("Foreground color");
    lbFont = new Label("Font");
    pBgColor.add(lbBgColor);
    pBgColor.add(chBgColor);
    pFgColor.add(lbFgColor);
    pFgColor.add(chFgColor);
    pFont.add(lbFont);
    pFont.add(chFont);
  }
  public void paint(Graphics g)
  {
    Dimension dimAppWndDimension = getSize();
    g.drawRect(0, 0,
      dimAppWndDimension.width  - 1,
      dimAppWndDimension.height - 1);
    super.paint(g);
  }
  public boolean action(Event evt, Object obj)
  {
    Choice ch;
    if(evt.target instanceof Choice)
    {
      ch = (Choice)evt.target;
      if(evt.target.equals(chBgColor))
      {
    if(ch.getSelectedIndex() == 0)
      pControlled.setBackground(
            Color.yellow);
    else if(ch.getSelectedIndex() == 1)
      pControlled.setBackground(
            Color.green);
    else if(ch.getSelectedIndex() == 2)
      pControlled.setBackground(
            Color.white);
      }
      else if(evt.target.equals(chFgColor))
      {
    if(ch.getSelectedIndex() == 0)
      pControlled.setForeground(
            Color.black);
    else if(ch.getSelectedIndex() == 1)
      pControlled.setForeground(
            Color.red);
    else if(ch.getSelectedIndex() == 2)
      pControlled.setForeground(
            Color.green);
      }
      else if(evt.target.equals(chFont))
      {
    if(ch.getSelectedIndex() == 0)
      ((FirstPanel)pControlled).szFontName
            = "TimesRoman";
    else if(ch.getSelectedIndex() == 1)
      ((FirstPanel)pControlled).szFontName
            = "Helvetica";
    else if(ch.getSelectedIndex() == 2)
      ((FirstPanel)pControlled).szFontName
            = "Courier";
      }
      else
      {
    return false;
      }
      pControlled.repaint();
      return true;
    }
    return false;
  }
}
class ControlPanel extends Panel
{
  Button btNext;
  Button btPrev;
  Button btBgColor;
  Button btFgColor;
  Button btFont;
  Panel pCard;
  public ControlPanel(Panel pCardPanel)
  {
    pCard = pCardPanel;
    setLayout(new GridLayout(2,3));
    btBgColor = new Button("Background Color");
    btFgColor = new Button("Foreground Color");
    btFont = new Button("Set Font");
    btNext = new Button("Next");
    btPrev = new Button("Prev");
    add(btBgColor);
    add(btFgColor);
    add(btFont);
    add(btNext);
    add(btPrev);
  }
  public boolean action(Event evt, Object obj)
  {
    if(evt.target instanceof Button)
    {
      if(evt.target.equals(btBgColor))
      {
    ((CardLayout)pCard.getLayout()).show(
            pCard, "BgColor");
      }
      else if(evt.target.equals(btFgColor))
      {
    ((CardLayout)pCard.getLayout()).show(
            pCard, "FgColor");
      }
      else if(evt.target.equals(btFont))
      {
    ((CardLayout)pCard.getLayout()).show(
            pCard, "Font");
      }
      else if(evt.target.equals(btNext))
      {
    ((CardLayout)pCard.getLayout()).next(
            pCard);
      }
      else if(evt.target.equals(btPrev))
      {
    ((CardLayout)pCard.getLayout()).
            previous(pCard);
      }
      else
      {
    return false;
      }
      return true;
    }
    return false;
  }
}

Исходный текст документа HTML, созданный для аплета Options системой Java WorkShop, представлен в листинге 2.

Листинг 2. Файл Options.tmp.html

<applet name="Options"
  code="Options"
  codebase=
"file:/E:/Sun/Articles/vol8/src/Options"
  width="500"
  height="600"
  align="Top"
  alt="If you had a java-enabled browser,
 you would see an applet here.">
 <hr>If your browser recognized the applet tag,
you would see an applet here.<hr>
</applet>


Описание текста
Работа с панелями
Создание панелей
Добавление панелей
Добавление компонент
Рисование в панели
Класс на базе Panel
Аплет Options
Исходный текст
Описание текста

Описание исходного текста аплета Options

Назад Вперед

Помимо основного класса Options в нашем аплете создается еще три класса для панелей с именами FirstPanel, CardPanel и ControlPanel.

Класс FirstPanel соответствует самой верхней панели, в которой отображается строка текста First panel. Классы CardPanel и ControlPanel испльзуются для создания панелей со списками и управляющими кнопками, соответственно. Мы будем рассматривать эти классы по отдельности.

Главный класс аплета Options

В главном классе аплета Options мы определили три поля с именами pPanel1, pCard и pControl:

FirstPanel   pPanel1;
CardPanel    pCard;
ControlPanel pControl;

В них хранятся ссылки на три класса, созданных нами для трех панелей.

Метод init

Прежде всего метод init устанавливает для окна аплета режим размещения GridLayout:

setLayout(new GridLayout(3, 1));

Окно аплета делится на три горизнтальные области, в которых мы будем размещать панели.

Панели создаются с помощью оператора new как объекты соответствующих классов, определенных в нашем приложении:

pPanel1 = new FirstPanel();
add(pPanel1);
pCard = new CardPanel(pPanel1);
add(pCard);
pControl = new ControlPanel(pCard);
add(pControl);

Для добавления панелей в окно аплета мы использовали метод add.

Далее метод init устанавливает начальные значения для цвета фона и текста верхней панели:

pPanel1.setBackground(Color.yellow);
pPanel1.setForeground(Color.black);

Обратите внимание, что мы вызываем методы setBackground и setForeground для объекта pPanel1.

После выполнения всех этих действий метод init перерисовывает окно аплета, вызывая метод repaint:

repaint();

Класс FirstPanel

Мы создали класс FirstPanel на базе класса Panel, определив в нем одно поле типа String и переопределив метод paint:

class FirstPanel extends Panel
{
  . . .
}

Текстовое поле szFontName хранит название шрифта, с использованием которого в окне верхней панели отображается текстовая строка:

String szFontName = "TimesRoman";

Метод paint определяет текущие размеры панели и рисует вокруг нее прямоугольную рамку:

Dimension dimAppWndDimension = getSize();
g.drawRect(0, 0,
  dimAppWndDimension.width  - 1,
  dimAppWndDimension.height - 1);

Далее метод paint выбирает в контекст отображения, связанный с панелью, шрифт с названием szFontName и рисует текстовую строку:

g.setFont(new Font(szFontName,
    Font.PLAIN, 24));
g.drawString("First panel", 10, 50);

Заметим, что сразу после запуска аплета рамка и строка будут нарисованы с использованием черного цвета, выбранного в контекст отображения панели по умолчанию. В дальнейшем вы можете изменить этот цвет при помощи соответствующей страницы блокнота, реализованного во второй панели.

Последнее действие, которое выполняет метод paint первой панели - вызов метода paint из родительского класса:

super.paint(g);

Это приводит к перерисовке окна аплета.

Класс CardPanel

С помощью класса CardPanel мы создали панель для блокнота, содержащего три страницы. Этот класс, так же как и предыдущий, создан на базе класса Panel.

Поля класса CardPanel

В полях pBgColor, pFgColor и pFont хранятся ссылки на панели страниц блокнота, которые мы разместим внутри панели класса CardPanel:

Panel pBgColor;
Panel pFgColor;
Panel pFont;

Кроме того, в поле pControlled хранится ссылка на верхнюю панель с текстовой строкой First Panel.

Panel pControlled;

Это поле будет проинициализировано конструктором класса CardPanel.

В следующих трех полях мы храним ссылки на списки класса Choice, предназначенные, соответственно, для выбора цвета текста, цвета фона и шрифта:

Choice chBgColor;
Choice chFgColor;
Choice chFont;

Три поля класса Label содержат ссылки на подписи к указанным выше спискам:

Label lbBgColor;
Label lbFgColor;
Label lbFont;

Конструктор класса CardPanel

При создании объекта класса CardPanel мы передаем конструктору ссылку на верхнюю панель, параметрами которой нужно управлять. Конструктор записывает эту ссылку в поле pControlled:

public CardPanel(Panel pControlledPanel)
{
  pControlled = pControlledPanel;
   . . .
}

Затем конструктор устанавливает режим размещения CardLayout, оставляя зазор по вертикали и горизонтали, равный пяти пикселам:

setLayout(new CardLayout(5, 5));

На следующем этапе мы создаем три панели для страниц блокнота и добавляем их в панель CardPanel, задавая имена:

pBgColor = new Panel();
pFgColor = new Panel();
pFont    = new Panel();
add("BgColor", pBgColor);
add("FgColor", pFgColor);
add("Font", pFont);

Теперь нам нужно создать и заполнить три списка, предназначенный для выбора цвета и шрифта. Эти списки создаются как объекты класса Choice:

chBgColor = new Choice();
chFgColor = new Choice();
chFont    = new Choice();

После создания списки наполняются текстовыми строками. В каждый список мы добавляем по три строки:

chBgColor.add("Yellow");
chBgColor.add("Green");
chBgColor.add("White");
chFgColor.add("Black");
chFgColor.add("Red");
chFgColor.add("Green");
chFont.add("TimesRoman");
chFont.add("Helvetica");
chFont.add("Courier");

Для того чтобы снабдить списки подписями, мы создаем три объекта класса Label:

lbBgColor = new Label("Background color");
lbFgColor = new Label("Foreground color");
lbFont = new Label("Font");

Эти объекты, а также списки добавляются на свои страницы блокнота (то есть в свои панели):

pBgColor.add(lbBgColor);
pBgColor.add(chBgColor);
pFgColor.add(lbFgColor);
pFgColor.add(chFgColor);
pFont.add(lbFont);
pFont.add(chFont);

На этом работа метода init заканчивается.

Метод action

Метод action обрабатывает события, возникающие в результате выбора новых значений из списков, расположенных на страницах блокнота. Схема обработки событий не имеет никаких особенностей.

Вначале метод action проверяет, что событие вызвано списком класса Choice:

if(evt.target instanceof Choice)
{
  . . .
    return true;
  }
  return false;
}

События, связанные с изменением цвета фона, обрабатываются следующим образом:

ch = (Choice)evt.target;
if(evt.target.equals(chBgColor))
{
  if(ch.getSelectedIndex() == 0)
    pControlled.setBackground(
    Color.yellow);
  else if(ch.getSelectedIndex() == 1)
    pControlled.setBackground(
    Color.green);
  else if(ch.getSelectedIndex() == 2)
    pControlled.setBackground(
    Color.white);
}

Здесь методsetBackground вызывается для объекта, ссылка на который передана конструктору класса и записана в поле pControlled. Это ссылка на панель, размещенную в верхней части окна нашего аплета.

Аналогичным образом изменяется цвет текста и рамки для верхней панели:

else if(evt.target.equals(chFgColor))
{
  if(ch.getSelectedIndex() == 0)
    pControlled.setForeground(
    Color.black);
else if(ch.getSelectedIndex() == 1)
    pControlled.setForeground(
    Color.red);
else if(ch.getSelectedIndex() == 2)
    pControlled.setForeground(
    Color.green);
}

Для изменения шрифта мы устанавливаем новое значение переменной поляszFontName, определенной в классе FirstPanel:

else if(evt.target.equals(chFont))
{
  if(ch.getSelectedIndex() == 0)
    ((FirstPanel)pControlled).szFontName
     = "TimesRoman";
  else if(ch.getSelectedIndex() == 1)
    ((FirstPanel)pControlled).szFontName
     = "Helvetica";
  else if(ch.getSelectedIndex() == 2)
    ((FirstPanel)pControlled).szFontName
     = "Courier";
}

Для того чтобы адресоваться к полю szFontName, нам пришлось выполнить явное преобразование типа ссылки pControlled.

Последнее действие, которое совершает метод action - это перерисовка окна верхней панели, которая выполняется с помощью метода repaint:

pControlled.repaint();

Класс ControlPanel

Класс ControlPanel создан для нижней панели с управляющими кнопками.

Поля класса ControlPanel

Следующие пять полей хранят ссылки на кнопки, управляющие страницами блокнота:

Button btNext;
Button btPrev;
Button btBgColor;
Button btFgColor;
Button btFont;

Поле pCard хранит ссылку на панель блокнота:

Panel pCard;

Эта ссылка инициализируется конструктором класса.

Конструктор класса ControlPanel

В задачу конструктора класса ControlPanel входит запоминание ссылки на панель блокнота, установка режима размещения компонент GridLayout, а также создание и добавление в нижнюю панель управляющих кнопок:

public ControlPanel(Panel pCardPanel)
{
  pCard = pCardPanel;
  setLayout(new GridLayout(2,3));
  btBgColor = new Button("Background Color");
  btFgColor = new Button("Foreground Color");
  btFont = new Button("Set Font");
  btNext = new Button("Next");
  btPrev = new Button("Prev");
  add(btBgColor);
  add(btFgColor);
  add(btFont);
  add(btNext);
  add(btPrev);
}

Кнопки располагаются в ячейках таблицы, содержащей две строки и три столбца. В целом конструктор класса ControlPanel не имеет никаких интересных особенностей.

Метод action

Метод action управляет работой блокнота, отображая его страницы.

Когда пользователь нажимает на кнопки, выбирающие страницы блокнота, метод action выдвигает нужную страницу на передний план с помощью метода show:

if(evt.target.equals(btBgColor))
{
  ((CardLayout)pCard.getLayout()).show(
    pCard, "BgColor");
}
else if(evt.target.equals(btFgColor))
{
  ((CardLayout)pCard.getLayout()).show(
  pCard, "FgColor");
}
else if(evt.target.equals(btFont))
{
  ((CardLayout)pCard.getLayout()).show(
    pCard, "Font");
}

В качестве первого параметра этому методу передается идентификатор панели блокнота, а в качестве второго - имя страницы, которую необходимо отобразить.

Циклический перебор страниц блокнота выполняется с помощью методов next и previous, соответственно:

else if(evt.target.equals(btNext))
{
  ((CardLayout)pCard.getLayout()).next(
    pCard);
}
else if(evt.target.equals(btPrev))
{
  ((CardLayout)pCard.getLayout()).
    previous(pCard);
}


Окна и диалоговые панели
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Окна и диалоговые панели

Назад Вперед

До сих пор мы рисовали только в окне аплета или в окнах панелей, расположенных внутри окна аплета. Однако есть и другая возможность - приложения Java, полноценные и аплеты, могут создавать обычные перекрывающиеся окна, такие, например, как окно браузера. Эти окна могут иметь меню (в отличие от окон аплетов). Пользователь может изменять размер таких окон при помощи мыши, перемещая рамку окна.

В составе библиотеки классов AWT имеется несколько классов, предназначенных для работы с окнами. Это класс Window, который произошел от класса Container, и его дочерние классы - Frame, Dialog и FileDialog (рис. 1).

pic01.gif (2857 bytes)

Рис. 1. Иерархия классов, предназначенных для создания окон

Окно, созданное на базе класса Frame, больше всего похоже на главное окно обычного приложения Windows. Оно может иметь главное меню, для него можно устанавливать форму курсора. Внутри такого окна можно рисовать. Так как окно класса Frame (так же как и другие окна AWT) произошли от класса Container, вы можете добавлять в них различные компоненты и панели, как мы это делали с окнами аплетов и панелей.

На базе класса Dialog создаются окна диалоговых панелей, очень похожих на обычные диалоговые панели Windows. Такие панели не могут иметь меню и обычно предназначены для запроса какой-либо информации у пользователя.

Класс FileDialog предназначен для создания диалоговых панелей диалоговые панели, с помощью которых можно выбирать файлы на локальных дисках компьютера.

Что же касается класса Window, то непосредственно этот класс редко применяется для создания окон, так как классы Frame, Dialog и FileDialog более удобны и обеспечивают все необходимые возможности.


Окна класса Frame
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Окна класса Frame

Назад Вперед

Ниже мы привели краткое описание класса Frame. Так как этот класс реализует интерфейс java.awt.MenuContainer, окно класса Frame может содержать меню.

Поля

С помощью полей класса Frame вы можете задавать для своего окна различные типы курсоров:

public final static int CROSSHAIR_CURSOR;
public final static int DEFAULT_CURSOR;
public final static int E_RESIZE_CURSOR;
public final static int HAND_CURSOR;
public final static int MOVE_CURSOR;
public final static int N_RESIZE_CURSOR;
public final static int NE_RESIZE_CURSOR;
public final static int NW_RESIZE_CURSOR;
public final static int S_RESIZE_CURSOR;
public final static int SE_RESIZE_CURSOR;
public final static int SW_RESIZE_CURSOR;
public final static int TEXT_CURSOR;
public final static int W_RESIZE_CURSOR;
public final static int WAIT_CURSOR;

Конструкторы

Для класса Frame определено два конструктора:

Создание окна без заголовка

public Frame();

Создание окна с заголовоком

public Frame(String title);

Методы

  • addNotify

Вызов метода createFrame

public void addNotify();

dispose

Удаление окна и освобождение связанных с ним ресурсов

public void dispose();

getCursorType

Определение типа курсора

public int getCursorType();
  • getIconImage

Получение пиктограммы, установленной для окна

public Image getIconImage();
  • getMenuBar

Получение ссылки на главное меню

public MenuBar getMenuBar();
  • getTitle

Получение заголовка окна

public String getTitle();
  • isResizable

Определение возможности изменения размеров окна пользователем

public boolean isResizable();
  • paramString

Получение строки параметров

protected String paramString();
  • remove

Удаление компоненты меню

public void remove(MenuComponent m);
  • setCursor

Установка типа курсора

public void setCursor(int cursorType);
  • setIconImage

Установка пиктограммы

public void setIconImage(Image image);
  • setMenuBar

Установка главного меню

public void setMenuBar(MenuBar mb);
  • setResizable

Включение или выключение возомжности изменения размеров окна

public void setResizable(boolean resizable);
  • setTitle

Установка заголовка окна

public void setTitle(String title);

Применение класса Frame

Для того чтобы создать свое окно на базе класса Frame, вы должны определить свой класс, унаследовав его от класса Frame следующим образом:

class MainFrameWnd extends Frame
{
  . . .
  public MainFrameWnd(String sTitle)
  {
    super(sTitle);
     . . .
    resize(400, 200);
  }
  . . .
}

Если мы будем создавать окно с заголовком, нам необходимо соответствующим образом определить конструктор класса этого окна. В частности, наш конструктор должен вызывать конструктор базового класса, передавая ему в качестве параметра строку заголовка окна. Напомним, что конструктор базового класса должен вызываться в конструкторе дочернего класса перед выполнением каких-либо других действий.

Обратите также внимание на вызов метода resize. Этот вызов необходим для задания размеров окна.

В конструкторе вы можете определить различные параметры создаваемого вами окна, например, указать форму курсора, пиктограмму, представляющую окно, задать меню, определить возможность изменения размеров окна и так далее. Мы остановимся подробнее на процедуре добавления меню к окну класса Frame, так как она требует пояснений. С изменением других характеристик окна вы справитесь самостоятельно.

При создании окна классов Frame и Dialog для них устанавливается режим размещения BorderLayout. Если вам нужен другой режим размещения, необходимо установить его явным образом.

Кроме того, созданное окно появится на экране только после вызова для него метода show.

Убрать окно с экрана вы можете методом hide. Этот метод прячет окно, но оставляет в памяти все связанные с ним ресурсы, поэтому вы сможете вновь отобразить спрятанное окно, вызвав метод show.

В отличие от метода hide, метод dispose удаляет окно и освобождает все связанные с ним ресурсы. Этот метод применяется для окончательного удаления окна с экрана и из памяти.

Еще одно замечание касается обработки операции уничтожения окна при помощи двойного щелчка левой клавиши мыши по системному меню окна или при помощи кнопки уничтожения окна, расположенной в правой части заголовка.

Когда пользователь пытается уничтожить окно класса Frame или Dialog подобным образом, возникает событие Event.WINDOW_DESTROY. Вы должны предусмотреть обработку этого события, выполняя действия, соответствующие логике работы вашего окна. Обычно окно уничтожается вызовом метода dispose, как это показано ниже:

public boolean handleEvent(Event evt)
{
  if(evt.id == Event.WINDOW_DESTROY)
  {
    dispose();
    return true;
  }
  else
    return super.handleEvent(evt);
}


Меню MenuBar
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Меню в окне класса Frame

Назад Вперед

Как мы уже говорили, окно класса Frame может иметь главное меню (Menu Bar) или, как еще говорят, строку меню. Главное меню создается на базе класса MenuBar, краткое описание которого приведено ниже.

Конструктор

public MenuBar();

Методы

  • add

Добавление меню в главное меню окна

public Menu add(Menu m);
  • addNotify

Вызов метода createMenuBar

public void addNotify();
  • countMenus

Определение количества меню, добавленных в главное меню

public int countMenus();
  • getHelpMenu

Получение ссылки на меню Help

public Menu getHelpMenu();
  • getMenu

Получение ссылки на меню с заданным номером

public Menu getMenu(int i);
  • remove

Удаление меню с заданным номером из главного меню

public void remove(int index);

Удаление компоненты меню

public void remove(MenuComponent m);
  • removeNotify

Извещение об удалении меню

public void removeNotify();
  • setHelpMenu

Установка меню Help

public void setHelpMenu(Menu m);

Работа с классом MenuBar

Для формирования главного меню окна вы должны создать объект класса MenuBar с помощью конструктора, а затем добавить в него отдельные меню.

Объект главного меню создается следующим образом:

MenuBar mbMainMenuBar;
mbMainMenuBar = new MenuBar();

Отдельные меню создаются на базе класса Menu, например:

Menu mnFile;
Menu mnHelp;
mnFile = new Menu("File");
mnHelp = new Menu("Help");

Создав меню, вы должны добавить в них строки. Для этого нужно вызвать метод add, передав ему в качестве параметра текст строки меню, например:

mnFile.add("New");
mnFile.add("-");
mnFile.add("Exit");

mnHelp.add("Content");
mnHelp.add("-");
mnHelp.add("About");

Далее сформированные меню добавляются в главное меню:

mbMainMenuBar.add(mnFile);
mbMainMenuBar.add(mnHelp);

И, наконец, теперь можно устанавливать главное меню в окне класса, созданного на базе класса Frame:

setMenuBar(mbMainMenuBar);


Класс Menu
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Класс Menu

Назад Вперед

Для того чтобы дать вам представление о том, что можно делать с меню, приведем краткое описание класса Menu:

Конструкторы

Создание меню с заданным названием
public Menu(String label);

Создание меню с заданным названием,которое может оставаться на экране после того как пользователь отпустил клавишу мыши

public Menu(String label, boolean tearOff);

Методы

  • add

Добавление элемента меню

public MenuItem add(MenuItem mi);

Добавление строки в меню

public void add(String label);
  • addNotify

Вызов метода createMenu

public void addNotify();
  • addSeparator

Добавление разделителя в меню

public void addSeparator();
  • countItems

Определение количества строк в меню

public int countItems();
  • getItem

Получение ссылки на элемент меню с заданным номером

public MenuItem getItem(int index);
  • isTearOff

Проверка, остается ли меню на экране после того как пользователь отпустил клавишу мыши

public boolean isTearOff();
  • remove

Удаление заданного элемента меню

public void remove(int index);

Удаление заданной компоненты меню

public void remove(MenuComponent item);
  • removeNotify

Извещение об удалении меню

public void removeNotify();

Работа с классом Menu

Метод addSeparator используется для добавления в меню разделительной строки. Аналогичный результат достигается и при добавлении в меню стоки "-":

mnHelp.add("-");

Заметим, что вы можете просто добавлять в меню строки по их названию, пользуясь методом add(String label), либо добавлять в меню элементы класса MenuItem, вызывая метод add(MenuItem mi).


Класс MenuItem
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Класс MenuItem

Назад Вперед

Класс MenuItem определяет поведение отдельных элементов меню.

Пользуясь методами класса MenuItem вы можете блокировать или разблокировать отдельные строки меню. Это нужно делать, например, если в данный момент функция, соответствующая строке меню, недоступна или не определена. Вы также можете изменять текстовые строки, соответствующие элементам меню, что может пригодиться для переопределения их назначения.

Конструктор

public MenuItem(String label);

Методы

  • addNotify

Вызов метода createMenuItem

public void addNotify();
  • disable

Блокирование элемента меню

public void disable();
  • enable

Разблокирование элемента меню

public void enable();

Блокирование или разблокирование элемента меню

public void enable(boolean cond);
  • getLabel

Получение текстовой строки меню

public String getLabel();
  • isEnabled

Проверка, является ли элемент меню заблокированным

public boolean isEnabled();
  • paramString

Получение строки параметров

public String paramString();
  • setLabel

Установка текстовой строки для элемента меню

public void setLabel(String label);


Диалоговые панели
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Создание диалоговых панелей

Назад Вперед

Диалоговые панели создаются на базе класса Dialog, краткое описание которого приведено ниже.

Конструкторы

Создание диалоговой панели без заголовка

public Dialog(Frame parent, boolean modal);

Создание диалоговой панели с заголовком

public Dialog(Frame parent,
  String title, boolean  modal);

Методы

  • addNotify

Вызов метода createDialog

public void addNotify();
  • getTitle

Получение строки заголовка диалоговой панели

public String getTitle();
  • isModal

Определение, является ли диалоговая панель модальной

public boolean isModal();
  • isResizable

Определение возможности изменения размеров окна диалоговой панели

public boolean isResizable();
  • paramString

Получение строки параметров

protected String paramString();

setResizable

Включение или выключение возможности изменения размеров окна диалоговой панели

public void setResizable(boolean resizable);
  • setTitle

Установка заголовка диалоговой панели

public void setTitle(String title);

Использование класса Dialog

Для того чтобы создать свою диалоговую панель, вы должны определить новый класс, унаследовав его от класса Dialog, как это показано ниже:

class MessageBox extends Dialog
{
  . . .
  public MessageBox(String sMsg,
    Frame  parent, String  sTitle,
    boolean  modal)
  {
   super(parent, sTitle, modal);
   . . .
   resize(200, 100);
   . . .
  }
}

В этом классе нужно определить конструктор, который вызывает конструктор базового метода класса Dialog и определяет размеры окна диалоговой панели. Кроме того, в конструкторе вы должны создать все необходимые компоненты для размещения внутри диалоговой панели (кнопки, списки, текстовые поля, переключатели и так далее), а также выполнить размещение этих компонент, установив нужный режим размещения.

Для окон класса Dialog устанавливается режим размещения BorderLayout. Если нужен другой режим размещения, необходимо установить его явным образом методом setLayout.

Для отображения окна диалоговой панели необходимо вызвать метод show. Чтобы спрятать диалоговой окно, применяйте метод hide. Метод dispose удаляет окно диалоговой панели окончательно и освобождает все связанные с ним ресурсы.

Когда пользователь пытается уничтожить окно диалоговой панели при помощи органов управления, расположенных в заголовке такого окна, возникает событие Event.WINDOW_DESTROY. Вы должны обработать его, обеспечив удаление окна диалоговой панели вызовом метода dispose, если, конечно, это соответствует логике работы вашей панели.


Приложение MenuApp
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Приложение MenuApp

Назад Вперед

Автономное приложение MenuApp, работающее под управлением интерпертатора Java, демонстрирует способы создания меню. В его окне (рис. 1) имеется панель с меню File и Help.

pic02.gif (2210 bytes)

Рис. 1. Главное окно автономного приложения MenuApp

В меню File мы добавили строки New и Exit, а также разделитель в виде горизонтальной линии (рис. 2).

pic03.gif (2431 bytes)

Рис. 2. Меню File

Меню Help (рис. 3) содержит строки Content и About. Между ними также имеется разделительная линия.

pic04.gif (2497 bytes)

Рис. 3. Меню Help

Если выбрать любую строку, кроме строки Exit из меню File, на экране появится диалоговая панель с названием выбранной строки и кнопкой OK (рис. 4).

pic05.gif (1942 bytes)

Рис. 4. Диалоговая панель, которая появляется при выборе строки New из меню File

Выбор строки Exit из меню File приводит к завершению работы приложения MenuApp.


Исходный текст
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Исходный текст приложения MenuApp

Назад Вперед

Исходный текст приложения MenuApp представлен в листинге 1.

Листинг 1. Файл MenuApp.java

import java.awt.*;
public class MenuApp
{
  public static void main(String args[])
  {
    MainFrameWnd frame =
      new MainFrameWnd("MenuApp");
    frame.setSize(
    frame.getInsets().left +
      frame.getInsets().right  + 320,
      frame.getInsets().top  +
      frame.getInsets().bottom + 240);
    frame.show();
  }
}
class MainFrameWnd extends Frame
{
  MenuBar mbMainMenuBar;
  Menu mnFile;
  Menu mnHelp;
  public MainFrameWnd(String sTitle)
  {
    super(sTitle);
    setSize(400, 200);
    setBackground(Color.yellow);
    setForeground(Color.black);
    setLayout(new FlowLayout());
    mbMainMenuBar = new MenuBar();
    mnFile = new Menu("File");
    mnFile.add("New");
    mnFile.add("-");
    mnFile.add("Exit");
    mnHelp = new Menu("Help");
    mnHelp.add("Content");
    mnHelp.add("-");
    mnHelp.add("About");
    mbMainMenuBar.add(mnFile);
    mbMainMenuBar.add(mnHelp);
    setMenuBar(mbMainMenuBar);
  }
  public void paint(Graphics g)
  {
    g.setFont(new Font(
      "Helvetica", Font.PLAIN, 12));
    g.drawString("Frame window", 10, 70);
    super.paint(g);
  }
  public boolean handleEvent(Event evt)
  {
    if(evt.id == Event.WINDOW_DESTROY)
    {
      setVisible(false);
      System.exit(0);
      return true;
    }
    else
      return super.handleEvent(evt);
  }
  public boolean action(Event evt, Object obj)
  {
    MenuItem mnItem;
    if(evt.target instanceof MenuItem)
    {
      mnItem = (MenuItem)evt.target;
      if(obj.equals("Exit"))
      {
        System.exit(0);
      }
      else if(obj.equals("New"))
      {
        MessageBox mbox;
        mbox = new MessageBox(
          "Item New selected",
          this, "Dialog from Frame", true);
        mbox.show();
      }
      else if(obj.equals("Content"))
      {
        MessageBox mbox;
        mbox = new MessageBox(
          "Item Content selected",
          this, "Dialog from Frame", true);
        mbox.show();
      }
      else if(obj.equals("About"))
      {
        MessageBox mbox;
        mbox = new MessageBox(
          "Item About selected",
          this, "Dialog from Frame", true);
        mbox.show();
      }
      else
        return false;
      return true;
    }
    return false;
  }
}
class MessageBox extends Dialog
{
  Label lbMsg;
  Button btnOK;
  public MessageBox(String sMsg,
    Frame  parent, String  sTitle,
    boolean  modal)
  {
    super(parent, sTitle, modal);
    resize(200, 100);
    setLayout(new GridLayout(2, 1));
    lbMsg = new Label(sMsg, Label.CENTER);
    add(lbMsg);
    btnOK = new Button("OK");
    add(btnOK);
  }
  public boolean handleEvent(Event evt)
  {
    if(evt.id == Event.WINDOW_DESTROY)
    {
      dispose();
      return true;
    }
    else
      return super.handleEvent(evt);
  }
  public boolean action(Event evt, Object obj)
  {
    Button btn;
    if(evt.target instanceof Button)
    {
      btn = (Button)evt.target;
      if(evt.target.equals(btnOK))
      {
        dispose();
      }
      else
        return false;
      return true;
    }
    return false;
  }
}


Описание текста
Окна и диалоговые панели
Окна класса Frame
Меню MenuBar
Класс Menu
Класс MenuItem
Диалоговые панели
Приложение MenuApp
Исходный текст
Описание текста

Описание исходного текста приложения MenuApp

Назад Вперед

Как мы уже говорили, приложение MenuApp работает автономно. Поэтому мы импортируем только класс java.awt.*, необходимый для работы с окнами:

import java.awt.*;

В нашем приложении определено три класса - MenuApp, MainFrameWnd и MessageBox.

Класс MenuApp

В главном классе приложения MenuApp мы определили только один метод main. Этот метод получает управление при запуске приложения.

Первым делом метод main создает объект класса MainFrameWnd, определенного в нашем приложении:

MainFrameWnd frame =
  new MainFrameWnd("MenuApp");

Этот класс, созданный на базе класса Frame, определяет поведение главного окна нашего приложения.

На втором шаге метод init настраивает размеры главного окна с учетом размеров внешней рамки и заголовка окна:

frame.setSize(frame.getInsets().left +
  frame.getInsets().right  + 320,
  frame.getInsets().top  +
  frame.getInsets().bottom + 240);

Поля left и right объекта класса Insets, ссылку на который возвращает метод getInsets, содержат ширину левой и правой части рамки окна, соответственно. Поле top содержит высоту верхней части рамки окна с учетом заголовка, а поле bottom - высоту нижней части рамки окна.

Для отображения окна фрейма мы вызываем метод show, как это показано ниже:

frame.show();

Класс MainFrameWnd

Класс MainFrameWnd создан на базе класса Frame:

class MainFrameWnd extends Frame
{
  . . .
}

В нем мы определили три поля, конструктор, методы paint, handleEvent и action.

Поля класса MainFrameWnd

Поле mbMainMenuBar предназанчено для хранения ссылки на главное меню приложения, создаваемое как объект класса MenuBar:

MenuBar mbMainMenuBar;

Поля mnFile и mnHelp хранят ссылки на меню File и Help, соответственно:

Menu mnFile;
Menu mnHelp;

Данные меню создаются на базе класса Menu.

Конструктор класса MainFrameWnd

В качестве единственного параметра конструктору класса MainFrameWnd передается заголовок создаваемого окна. В первой исполняемой строке наш конструктор вызывает конструктор из базового класса, передавая ему строку заголовка через параметр:

public MainFrameWnd(String sTitle)
{
  super(sTitle);
  . . .
}

Далее конструктор определяет размеры окна, вызывая для него метод setSize:

setSize(400, 200);

Затем мы устанавливаем для нашего окна желтый цвет фона и черный цвет изображения:

setBackground(Color.yellow);
setForeground(Color.black);

По умолчанию для окон класса Frame устанавливается режим добавления компонент BorderLayout. Мы изменяем этот режим на FlowLayout, вызывая метод setLayout:

setLayout(new FlowLayout());

Далее конструктор приступает к формированию главного меню окна. Это меню создается как объект класса MenuBar:

mbMainMenuBar = new MenuBar();

Затем мы создаем и наполняем меню "File":

mnFile = new Menu("File");
mnFile.add("New");
mnFile.add("-");
mnFile.add("Exit");

Это меню создается на базе класса Menu. Обратите внимание, что между строками New и File расположен разделитель.

Аналогичным образом мы добавляем в главное меню другое меню - "Help":

mnHelp = new Menu("Help");
mnHelp.add("Content");
mnHelp.add("-");
mnHelp.add("About");

После своего окончательного формирования меню "File" и "Help" добавляются в главное меню окна mbMainMenuBar:

mbMainMenuBar.add(mnFile);
mbMainMenuBar.add(mnHelp);

И, наконец, когда главное меню будет сформировано, оно подключается к окну вызовом метода setMenuBar, как это показано ниже:

setMenuBar(mbMainMenuBar);

Метод paint

Метод paint получает в качестве параметра ссылку на контекст отображения, пригодный для рисования в нашем окне. Пользуясь этим контекстом, мы устанавливаем шрифт текста и рисуем текстовую строку. Затем мы вызываем метод paint из базового класса Frame, на основе которого создан наш класс MainFrameWnd:

public void paint(Graphics g)
{
  g.setFont(new Font(
    "Helvetica", Font.PLAIN, 12));
  g.drawString("Frame window", 10, 70);
  super.paint(g);
}

Метод handleEvent

Для того чтобы определить реакцию окна на попытку пользователя закрыть окно с помощью органов управления, расположенных в заголовке окна, или другим способом, мы переопределили метод handleEvent.

При получении кода события Event.WINDOW_DESTROY (удаление окна) мы скрываем окно, вызывая метод setVisible с параметром false.

Затем с помощью статического метода exit класса System мы завершаем работу интерпретатора:

public boolean handleEvent(Event evt)
{
  if(evt.id == Event.WINDOW_DESTROY)
  {
    setVisible(false);
    System.exit(0);
    return true;
  }
  else
    return super.handleEvent(evt);
}

Метод action

Этот метод обрабатывает события, возникающие при выборе строка из меню.

В начале своей работы метод action проверяет, действительно ли событие вызвано меню:

MenuItem mnItem;
if(evt.target instanceof MenuItem)
{
  . . .
}
return false;

Если это так, в поле mnItem сохраняется ссылка на элемент меню, вызвавший событие:

mnItem = (MenuItem)evt.target;

Тем не менее, для определения строки, выбранной пользователем, нам достаточно проанализировать второй параметр метода action:

if(obj.equals("Exit"))
{
  System.exit(0);
}
else if(obj.equals("New"))
{
  MessageBox mbox;
  mbox = new MessageBox(
    "Item New selected",
    this, "Dialog from Frame", true);
  mbox.show();
}
else if(obj.equals("Content"))
{
  . . .
}
else if(obj.equals("About"))
{
  . . .
}

В данном случае второй параметр метода action будет представлять собой ссылку на строку, выбранную из меню, поэтому для определения выбранной строки мы можем выполнить простое сравнение методом equals.

Если пользователь выбрал из меню File строку Exit, мы вызываем метод System.exit, предназначенный для завершения работы виртуальной машины Java.

В том случае когда пользователь выбирает любую другую строку из меню, метод action создает диалоговую панель на базе определенного нами класса MessageBox. В этой диалоговой панели отображаетя название выбранной строки меню.

Заметим, что сразу после создания конструктором диалоговая панель не появляется на экране. Мы отображаем ее, вызывая метод show.

Класс MessageBox

Для отображения названий выбранных строк меню мы создаем диалоговую панель, определив свой класс MessageBox на базе класса Dialog, как это показано ниже:

class MessageBox extends Dialog
{
  . . .
}

В классе MessageBox есть два поля, конструктор, методы handleEvent и action.

Поля класса MessageBox

Внутри диалоговой панели мы расположили текстовое поле класса Label, предназначенное для отображения сообщения, и кнопку с надписью OK, с помощью которой можно завершить работу диалоговой панели.

Ссылка на текстовое поле хранится в поле lbMsg, на кнопку - в поле btnOK.

Конструктор класса MessageBox

Наш конструктор создает диалоговую панель с заданным сообщением внутри нее. Ссылка на строку сообщения передается конструктору через первый параметр. Остальные параметры используются конструктором базового класса Dialog для создания диалоговой панели:

super(parent, sTitle, modal);

После вызова конструктора из базового класса наш конструктор устанавливает размеры окна созданной диалоговой панели, вызывая метод resize:

resize(200, 100);

Отменяя установленный по умолчанию режим размещения компонент BorderLayout, конструктор устанавливает режим GridLayout:

setLayout(new GridLayout(2, 1));

Окно диалоговой панели при этом разделяется на две части по горизонтали. В верхнюю часть добавляется текстовое поле для отображения сообщения, в нижнюю - кнопка OK:

lbMsg = new Label(sMsg, Label.CENTER);
add(lbMsg);
btnOK = new Button("OK");
add(btnOK);

Метод handleEvent класса MessageBox

Когда пользователь пытается закрыть окно диалоговой панели, например, сделав двойной щелчок левой клавишей мыши по системному меню или одиночный щелчок по кнопке удаления окна, возникает событие Event.WINDOW_DESTROY. Мы его обрабатываем следующим образом:

if(evt.id == Event.WINDOW_DESTROY)
{
  dispose();
  return true;
}
else
  return super.handleEvent(evt);

Вызывая метод dispose, мы удаляем окно диалоговой панели и освобождаем все связанные с ним ресурсы.

Метод action класса MessageBox

Если пользователь нажимает кнопку OK, расположенную в окне диалоговой панели, метод action вызывает для панели метод dispose, удаляя эту панель с экрана и из памяти:

if(evt.target.equals(btnOK))
{
  dispose();
}