- •Кен Арнольд Джеймс Гослинг Дэвид Холмс Язык программирования 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
- •Приложение в Полезные таблицы
5.13.2. Явное приведение и instanceof
Когда значение одного типа не может быть присвоено переменной другого типа посредством неявного приведения, довольно часто можно воспользоваться явным приведением типов (cast). Явное приведение требует, чтобы новое значение нового типа как можно лучше соответствовало старому значению старого типа. Некоторые явные приведения недопустимы(вы не сможете преобразовать boolean в int), однако разрешается, например, явное приведение double к значению типа long, как показано в следующем фрагменте:
double d = 7.99;
long l = (long)d;
Когда значение с плавающей точкой преобразуется к целому типу, его дробная часть отбрасывается; например, (int)-72.3 равняется –72. В классе Math имеются методы, которые иначе осуществляют округление чисел с плавающей точкой при преобразовании в целое— см. раздел “Класс Math”.
Значение double также может явно преобразовываться к типу float, а значение целого типа— к меньшему целому типу. При приведении double к float возможна потеря точности или же появление нулевого или бесконечного значения вместо существовавшего ранее конечного.
Приведение целых типов заключается в “срезании” их старших битов. Если значение большего целого умещается в меньшем типе, к которому осуществляется преобразование, то ничего страшного не происходит. Однако если величина более широкого целого типа лежит за пределами более узкого типа, то потеря старших битов изменяет значение, а возможно— и знак. Фрагмент:
short s = -134;
byte b = (byte)s;
System.out.println("s = " + s + ", b = " + b);
выводит следующий результат (поскольку старшие биты s теряются при сохранении значения в b):
s = -134, b = 122
char можно преобразовать к любому целому типу и наоборот. При приведении целого типа в char используются только младшие 16 бит, а остальные биты отбрасываются. При преобразовании char в целый тип старшие 16 бит заполняются нулями. Тем не менее впоследствии работа с этими битами осуществляется точно так же, как и с любыми другими. В приведенном ниже фрагменте программы максимальный символ Unicode преобразуется к типу int (неявно) и к типу short (явно). Значение типа int (0x0000ffff) оказывается положительным, поскольку старшие биты символа обнулены. Однако при приведении к типу short получается отрицательная величина, так как старшим битом типа short является знаковый бит:
class CharCast {
public static void main(String[] args) {
int i = '\uffff';
short s = (short)'\uffff';
System.out.println("i = " + i);
System.out.println("s = " + s);
}
}
А вот как выглядит результат работы:
i = 65535
s = -1
Явное приведение типов может применяться и к объектам. Хотя объект расширенного типа разрешается использовать вместо объекта супертипа, обратное, вообще говоря, неверно. Предположим, у вас имеется следующая иерархия объектов:
Ссылка типа Coffee не обязательно относится к типу Mocha— объект также может иметь тип Latte. Следовательно, неверно, вообще говоря, ставить ссылку на объект типа Coffee там, где требуется ссылка на объект типа Mocha. Подобное приведение называется сужением (narrowing), или понижающим приведением, в иерархии классов. Иногда его также называют ненадежным приведением (unsafe casting), поскольку оно не всегда допустимо. Переход от типа, расположенного ниже в иерархии, к расположенному выше называется повышающим приведением типа; кроме того, употребляется термин надежное приведение, поскольку оно работает во всех случаях.
Но иногда вы совершенно точно знаете, что объект Coffee на самом деле является экземпляром класса Mocha. В этом случае можно осуществлять явное понижающее приведение. Это делается следующим образом:
Mocha fancy = (Mocha)joe;
Если такое приведение сработает (то есть ссылка joe действительно указывает на объект типа Mocha), то ссылка fancy будет указывать на тот же объект, что и joe, однако с ее помощью можно получить доступ к дополнительным функциям, предоставляемым классом Mocha. Если же преобразование окажется недопустимым, будет возбуждено исключение ClassCastException. В случае, если приведение даже потенциально не может быть правильным (например, если бы Mocha вообще не являлся подклассом того класса, к которому относится joe), будет выдано сообщение об ошибке во время компиляции программы. Таким образом предотвращаются возможные проблемы, связанные с неверными предположениями по поводу иерархии классов.
Иногда метод не требует, чтобы объект относился к расширенному типу, но может предоставить объектам расширенного типа дополнительные функции. Можно выполнить приведение типа и обработать исключение, однако использование исключений для подобных целей оказывается сравнительно медленным и потому считается проявлением плохого стиля. Для определения того, относится ли объект к конкретному типу, применяется метод instanceof, который возвращает true для допустимых преобразований:
public void quaff(Coffee joe) {
// ...
if (joe instanceof Mocha) {
Mocha fancy = (Mocha)joe;
// ... использовать функциональность Mocha
}
}
Ссылка null не указывает ни на какой конкретный объект, так что результат выражения
null instanceof Type
всегда равен false для любого типа Type.