- •Кен Арнольд Джеймс Гослинг Дэвид Холмс Язык программирования 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.1 Имена
Для перевода имен методов и полей на язык C используются полные имена, включающие названия пакетов, в которых все точки (.) заменяются подчеркиваниями (_). В тех языках, где не поддерживается возможность перегрузки методов (к ним относится C) вы не сможете реализовать в классе несколько методов с одинаковыми именами, поскольку им будет соответствовать одно и то же имя функции.
Аналогично переводятся и имена типов— за тем исключением, что перед именем типа ставится префикс Class. В программе на C тип для LockableFile будет называться Classlocal_LockableFile. Для каждого класса также необходим дескриптор (handle), поскольку он используется для внутреннего представления ссылок. Имя дескриптора совпадает с именем класса, но вместо префикса Class используется префикс H. Таким образом, тип дескриптора для LockableFile будет называться Hlocal_LockableFile.
Символы имен, относящиеся к набору ASCII (символы, меньшие или равные \u007f) переходят в C и в имена пакетов без изменений. Все остальные символы переводятся в вид _0dddd, где d— цифры, используемые в символьном представлении Java. Например, символ г (код \u00e3) будет представлен идентификатором _000e3. Косая черта (/) в имени пакета переходит в символ подчеркивания (_).
А.2.2 Методы
Каждый родной метод представляется в виде функции. Например, метод lock будет называться local_LockableFile_lock и иметь соответствующие параметры. Первый параметр функции— это дескриптор объекта, для которого вызывается метод (ссылка this). Для статических методов такой дескриптор всегда равен null. Ниже дескрипторы рассматриваются более подробно.
Для вызова методов нужен дополнительный слой в виде файлов-заглушек (stub files). Последние также генерируются утилитой javah, но с параметром -stubs:
javah -stubs local.LockableFile
Такая команда генерирует исходный файл на языке C, который должен быть скомпилирован и загружен в динамическую библиотеку вместе в реализациями родных методов. Имя этого файла совпадает с именем заголовочного файла, однако расширение h изменяется на c— в нашем случае это будет файл local_LockableFile.c.
А.2.3 Типы
В приведенной ниже таблице показано соответствие между примитивными типами Java и типами языка C, когда они используются в качестве параметров методов или полей (согласование типов для массивов рассматривается ниже).
Тип Java |
Тип C |
boolean |
long |
byte |
long |
short |
long |
int |
long |
long |
int64_t |
float |
float |
double |
double |
char |
long |
Классы Java представляются в языке C структурами (struct). Все нестатические поля класса являются членами структуры, а их имена совпадают с именами в Java (за исключением символов Unicode, отображаемых в эквиваленты _0dddd). Это означает, что класс, содержащий родные методы, не может иметь два нестатических поля с одинаковыми именами; в противном случае структура на языке C содержала бы члены с одинаковыми именами, что запрещено.
Проблема возникает с теми классами, которые скрывают поля суперклассов— кстати, еще одна причина, по которой не следует скрывать имена полей. Тем не менее, проблема относится даже к тем классам, которые содержат закрытые поля с тем же именем, поскольку такие поля присутствуют в структуре наравне со всеми остальными. Вы не сможете выяснить, актуальна эта проблема или нет, пока она не возникнет при написании родного метода. Дело обстоит еще хуже, если скрываемые поля находятся в суперклассе, который невозможно изменить. В таких случаях дело заходит в тупик— вы не сможете написать родной метод без модификации имен полей класса.
Каждая статическая константа с атрибутом final представлена константой #define с префиксами(именем пакета и класса). Статические поля, не являющиеся final, не переводятся ни во что. Например, тип и константы для класса LockableFile определяются в заголовочном файле следующим образом:
typedef struct Classlocal_LockableFile {
struct Hjava_lang_String *path;
/* недоступное статическое поле: separator */
/* недоступное статическое поле: separatorChar */
/* недоступное статическое поле: pathSeparator */
/* недоступное статическое поле: pathSeparatorChar */
#define local_LockableFile_READ 0L
#define local_LockableFile_WRITE 1L
long fd;
} Classlocal_LockableFile;
Ссылки на объекты представляются типом “дескриптор”, в составном имени которого Class заменяется на H. Ссылка на класс LockableFile будет называться Hlocal_LockableFile. Макрос unhand получает дескриптор и возвращает указатель на структуру, которая представляется этим дескриптором.
Ниже приведены сигнатуры функций языка C, в которых ниже мы определим родные методы класса LockableFile:
extern void local_Lockable_File_lock(
struct Hlocal_LockableFile *, long);
extern void local_Lockable_File_unlock(
struct Hlocal_LockableFile *);
В Java об ошибках сигнализируют исключения. В языке C исключений нет. Чтобы возбудить исключение из C, следует вызвать функцию SignalError и затем выйти. Runtime-система Java обнаруживает и возбуждает исключение, о котором сигнализировала функция SignalError. Ниже вы увидите несколько примеров того, как это делается.