- •Кен Арнольд Джеймс Гослинг Дэвид Холмс Язык программирования Java
- •Глава 1 первое знакомство с java 6
- •Глава 2 классы и объекты 29
- •Глава 3 расширение классов 47
- •Глава 4 интерфейсы 70
- •Глава 5 лексемы, операторы и выражения 78
- •Глава 6 порядок выполнения 105
- •Глава 7 исключения 113
- •Глава 8 строки 121
- •Глава 9 потоки 134
- •Глава 10 пакеты 156
- •Глава 11 пакет ввода/вывода 158
- •Глава 12 стандартные вспомогательные средства 183
- •Глава 13 применение типов в программировании 205
- •Глава 14 системное программирование 218
- •Глава1 первое знакомство сjava
- •1.1. С самого начала
- •1.2.Переменные
- •1.3. Комментарии
- •1.4.Именованные константы
- •1.4.1. Символы Unicode
- •1.5.Порядок выполнения
- •1.6.Классы и объекты
- •1.6.1.Создание объектов
- •1.6.2.Статические поля
- •1.6.3.Сборщик мусора
- •1.7.Методы и параметры
- •1.7.1.Вызов метода
- •1.7.2.Ссылка this
- •1.7.3.Статические методы
- •1.8.Массивы
- •1.9.Строковые объекты
- •1.10.Расширение класса
- •1.10.1.Класс Object
- •1.10.2.Вызов методов суперкласса
- •1.11. Интерфейсы
- •1.12.Исключения
- •1.13.Пакеты
- •1.14.Инфраструктура Java
- •1.15.Прочее
- •Глава 2 классы и объекты
- •2.1. Простой класс
- •2.2. Поля
- •2.3. Управление доступом и наследование
- •2.4. Создание объектов
- •2.5. Конструкторы
- •2.6. Методы
- •2.6.1. Значения параметров
- •2.6.2. Применение методов для ограничения доступа
- •2.7. Ссылка this
- •2.8. Перегрузка методов
- •2.9. Статические члены
- •2.9.1. Блоки статической инициализации
- •2.9.2. Статические методы
- •2.10. Сборка мусора и метод finalize
- •2.10.1. Метод finalize
- •2.10.2. Восстановление объектов в методе
- •2.11. Метод main
- •2.12. Метод toString
- •2.13. Родные методы
- •Глава 3 расширение классов
- •3.1. Расширенный класс
- •3.2. Истинное значение protected
- •3.3. Конструкторы в расширенных классах
- •3.3.1. Порядок вызова конструкторов
- •3.4. Переопределение методов и скрытие полей
- •3.4.1. Ключевое слово super
- •3.5. Объявление методов и классов с ключевым словом final
- •3.6. Класс Object
- •3.7. Абстрактные классы и методы
- •3.8. Дублирование объектов
- •3.9. Расширение классов: когда и как
- •3.10. Проектирование расширяемого класса
- •Глава 4 интерфейсы
- •4.1. Пример интерфейса
- •4.2. Одиночное и множественное наследование
- •4.3. Расширение интерфейсов
- •4.3.1. Конфликты имен
- •4.4. Реализация интерфейсов
- •4.5. Использование реализации интерфейса
- •4.6. Для чего применяются интерфейсы
- •Глава 5 лексемы, операторы и выражения
- •5.1. Набор символов
- •5.2. Комментарии
- •5.3. Лексемы
- •5.4. Идентификаторы
- •5.4.1. Зарезервированные слова Java
- •5.5. Примитивные типы
- •5.6. Литералы
- •5.6.1. Ссылки на объекты
- •5.6.2. Логические значения
- •5.6.3. Целые значения
- •5.6.4. Значения с плавающей точкой
- •5.6.5. Символы
- •5.6.6. Строки
- •5.7. Объявления переменных
- •5.7.1. Значение имени
- •5.8. Массивы
- •5.8.1. Многомерные массивы
- •5.9. Инициализация
- •5.9.1. Инициализация массивов
- •5.10. Приоритет и ассоциативность операторов
- •5.11. Порядок вычислений
- •5.12. Тип выражения
- •5.13. Приведение типов
- •5.13.1. Неявное приведение типов
- •5.13.2. Явное приведение и instanceof
- •5.13.3. Строковое приведение
- •5.14. Доступ к членам
- •5.15. Арифметические операторы
- •5.15.1. Целочисленная арифметика
- •5.15.2. Арифметика с плавающей точкой
- •5.15.3. Арифметика с плавающей точкой и стандарт ieee-754
- •5.15.4. Конкатенация строк
- •5.16. Операторы приращения и уменьшения
- •5.17. Операторы отношения и условный оператор
- •5.18. Поразрядные операции
- •5.19. Условный оператор
- •5.20. Операторы присваивания
- •5.21. Имена пакетов
- •Глава 6 порядок выполнения
- •6.1. Операторы и блоки
- •6.2. Оператор if-else
- •6.3. Оператор switch
- •6.4. Цикл while и do-while
- •6.5. Оператор for
- •6.6. Метки
- •6.7. Оператор break
- •6.8. Оператор continue
- •6.9. Оператор return
- •Глава 7 исключения
- •7.1. Создание новых типов исключений
- •7.2. Оператор throw
- •7.3. Условие throws
- •7.4. Операторы try, catch и finally
- •7.4.1. Условие finally
- •7.5. Когда применяются исключения
- •Глава 8 строки
- •8.1. Основные операции со строками
- •8.2. Сравнение строк
- •8.3. Вспомогательные методы
- •8.4. Создание производных строк
- •8.5. Преобразование строк
- •8.6. Строки и символьные массивы
- •8.7. Строки и массивы byte
- •8.8. Класс StringBuffer
- •8.8.1. Модификация буфера
- •8.8.2. Извлечение данных
- •8.8.3. Работа с емкостью буфера
- •Глава 9 потоки
- •9.1. Создание потоков
- •9.2. Синхронизация
- •9.2.1. Методы synchronized
- •9.2.2. Операторы synchronized
- •9.3. Методы wait и notify
- •9.4. Подробности, касающиеся wait и notify
- •9.5. Планирование потоков
- •9.6. Взаимная блокировка
- •9.7. Приостановка потоков
- •9.8. Прерывание потока
- •9.9. Завершение работы потока
- •9.10. Завершение приложения
- •9.11. Использование Runnable
- •9.12. Ключевое слово volatile
- •9.13. Безопасность потоков и ThreadGroup
- •9.14. Отладка потоков
- •Глава 10 пакеты
- •10.1. Имена пакетов
- •10.2. Пакетный доступ
- •10.3. Содержимое пакета
- •Глава 11 пакет ввода/вывода
- •11.1. Потоки
- •11.2. Класс InputStream
- •11.3. Класс OutputStream
- •11.4. Стандартные типы потоков
- •11.5. Фильтрующие потоки
- •11.6. Класс PrintStream
- •11.7. Буферизованные потоки
- •11.8. Байтовые потоки
- •11.9. Класс StringBufferInputStream
- •11.10. Файловые потоки и FileDescriptor
- •11.11. Конвейерные потоки
- •11.12. Класс Seq uenceInputStream
- •11.13. Класс LineNumberInputStream
- •11.14. Класс PushbackInputStream
- •11.15. Класс StreamTokenizer
- •11.16. Потоки данных
- •11.16.1. Классы потоков данных
- •11.17. Класс RandomAccessFile
- •11.18. Класс File
- •11.19. Интерфейс FilenameFilter
- •11.20. Классы ioException
- •Глава 12 стандартные вспомогательные средства
- •12.1. Класс BitSet
- •12.2. Интерфейс Enumeration
- •12.3. Реализация интерфейса Enumeration
- •12.4. Класс Vector
- •12.5. Класс Stack
- •12.6. Класс Dictionary
- •12.7. Класс Hashtable
- •12.8. Класс Properties
- •12.9. Классы Observer/Observable
- •12.10. Класс Date
- •12.11. Класс Random
- •12.12. Класс String Tokenizer
- •Глава 13 применение типов в программировании
- •13.1. Класс Class
- •13.2. Загрузка классов
- •13.3. Классы-оболочки: общий обзор
- •13.4. Класс Boolean
- •13.5. Класс Character
- •13.6. Класс Number
- •13.7. Класс Integer
- •13.8. Класс Long
- •13.9. Классы Float и Double
- •Глава 14 системное программирование
- •14.1. Стандартный поток ввода/вывода
- •14.2. Управление памятью
- •14.3. Системные свойства
- •14.4. Создание процессов
- •14.5. Класс Runtime
- •14.6. Разное
- •14.7. Безопасность
- •14.8. Класс Math
- •Приложение а Родные методы
- •А.1 Обзор
- •А.2.1 Имена
- •А.2.2 Методы
- •А.2.3 Типы
- •А.2.5 Средства безопасности
- •А.2.6 Работа с памятью
- •А.3 Пример
- •А.3.1 Внутреннее строение LockableFile
- •А.4 Строки
- •А.5 Массивы
- •А.6 Создание объектов
- •А.7 Вызов методов Java
- •А.8 Последнее предупреждение
- •Приложение б Runtime-исключения в Java
- •Б.1 Классы RuntimeException
- •Б.2 Классы Error
- •Приложение в Полезные таблицы
А.2.5 Средства безопасности
Средства безопасности языка Java не имеют аналогов в C. Вы полностью отвечаете за работу программы на C (как это обычно бывает) без какой-либо автоматической помощи со стороны Java.
А.2.6 Работа с памятью
Родные методы могут создавать новые объекты Java с помощью функций, описанных ниже.
А.3 Пример
Давайте рассмотрим возможную реализацию родных методов для класса LockableFile. Прежде всего, мы должны сгенерировать заголовочный файл и файл-заглушку и скомпилировать последний. Затем нужно написать сами реализации методов. Например, метод lock может быть реализован следующим образом:
#include "local_LockableFile.h"
#include <<javaString.h>>
#include <<fcntl.h>>
#include <<errno.h>>
void
local_LockableFile_lock(
struct Hlocal_LockableFile *this_h,
long mode)
{
Classlocal_LockableFile *this = unhand(this_h);
struct flock lock;
if (this->>fd == -1 && !open_fd(this))
return; /* произошла ошибка */
if (!setup_lock(&lock, mode))
return;
if(fcntl(this->>fd, F_SETLKW, &lock) == -1)
SignalError(EE(),
"java/io/IOException", strerror(errno));
}
Сначала мы включаем нужные заголовочные файлы— сгенерированный файл для LockableFile, вспомогательный заголовочный файл для работы со строками <<javastring.h>>, системный заголовочный файл <<fcntl.h>>, определяющий вызовы для осуществления блокировки в POSIX, и системный заголовочный файл <<errno.h>> для обработки ошибок, полученных в ходе вызовов системных функций.
Первая строка в реализации метода lock переводит дескриптор this_h в указатель на структуру Classlocal_LockableFile, для чего используется макрос unhand, который возвращает объект, соответствующий данному дескриптору. Ссылкам null в Java ставится в соответствие указатели на дескрипторы, которые также равны NULL. Чтобы убедиться в том, что передача ссылки null не приведет к ошибкам, необходимо проверить дескриптор перед тем, как вызывать для него макрос unhand— это демонстрируется в последующих примерах.
Во второй строке local_LockableFile_lock объявляется структура flock. Структура flock используется для работы с блокировкой в POSIX. Реализации open_fd и setup_lock приводятся в разделе “Внутреннее строение LockableFile”.
Далее мы проверяем, имеется ли файловый дескриптор. Если он отсутствует и функция open_fd не может открыть файл, видимо, было возбуждено исключение, сигнализирующее об ошибке, поэтому мы просто выходим из функции. Если же дескриптор имеется, то структуру flock необходимо подготовить вызовом внутренней функции setup_lock. Вызов функции также может закончиться неудачей (например, если mode имеет недопустимое значение) и возбуждением исключения— и в этом случае мы выходим из функции. Функции open_fd и setup_lock являются частью кода, специфичного для POSIX.
Затем мы пытаемся заблокировать файл с помощью режима F_SETLKW функции POSIX с именем fcntl, который при необходимости ожидает возможности блокировки. Если fcntl возвращает -1, то попытка блокировки оказалась неудачной, и мы возбуждаем исключение, вызывая runtime-функцию Java с именемSignalError:
void SignalError(ExecEnv *exenu, char *type, char *constructor)
Сигнализирует о том, что после выхода из родного метода должно быть возбуждено исключение. Структура exenu обычно возвращается функцией EE и представляет текущее состояние среды. Параметр type является полным именем класса возбуждаемого объекта-исключения, в котором каждая точка (.) заменяется чертой (/). Последний параметр содержит строковое описание исключения или NULL при его отсутствии.
В нашем случае используется значение функции POSIX с именем strerror, которая возвращает строку с описанием номера ошибки. Практически это самое лучшее, что мы можем сделать для описания ошибок в родных методах.
Функция SignalError лишь подготавливает исключение; она не возбуждает его. В языке C исключения не предусмотрены, поэтому возбудить их из программы невозможно. После выхода из функции, содержащей реализацию родного метода, runtime-система проверяет флаги и по ним определяет, был ли получен сигнал о возбуждении исключения. Если такой сигнал получен, то runtime-система возбуждает исключение. Подобная схема позволяет в программе на C выполнить необходимые завершающие действия после “возбуждения” исключения. В функции local_LockableFile_lock такие действия не требуются, поэтому после “возбуждения” исключения мы просто выходим из нее.
Реализация unlock выглядит проще. Мы подготавливаем структуру flock и вызываем fcntl для режима F_UNLCK (снятие блокировки). И снова при неудаче возбуждается исключение, содержащее строку с описанием ошибки:
void
local_LockableFile_unlock(
struct Hlocal_LockableFile *this_h)
{
Classlocal_LockableFile *this = unhand(this_h);
struct flock lock;
lock.l_whence = lock.l_start = lock.l_len = 0;
lock.l_type = F_UNLCK;
if (fcntl(this->>fd, F_SETLKW, &lock) == -1)
SignalError(EE(),
"java/io/IOException", strerror(errno));
}
В класс LockableFile можно внести ряд усовершенствований. Например, создать функцию для проверки того, заблокирован ли файл и если да, то каким программным потоком. Можно сконструировать специальный вариант lock без ожидания, который лишь осуществляет блокировку, если она возможна, а в противном случае завершает свою работу. Или создать отдельные исключения для каждой ошибки, чтобы ошибка “файл не существует” отличалась от “доступ запрещен”.
Упражнение А.1
Если у вас имеется доступ к системе, отличной от POSIX и поддерживающей блокировку файлов, реализуйте класс LockableFile с использованием ее механизмов.
Упражнение А.2
Если вы работаете только с POSIX-совместимыми системами или выполнили упражнение А.1, включите в класс описанные выше возможности.