
- •Кен Арнольд Джеймс Гослинг Дэвид Холмс Язык программирования 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
- •Приложение в Полезные таблицы
4.2. Одиночное и множественное наследование
В языке Java новый класс может расширять всего один суперкласс— такая модель носит название одиночного наследования. Расширение класса означает, что новый класс наследует от своего суперкласса не только контракт, но и реализацию. В некоторых объектно-ориентированных языках используется множественное наследование, при котором новый класс может иметь два и более суперклассов.
Множественное наследование оказывается полезным в тех случаях, когда требуется наделить класс новыми возможностями и при этом сохранить большую часть (или все) старых свойств. Однако при наличии нескольких суперклассов возникают проблемы, связанные с двойственным наследованием. Например, рассмотрим следующую иерархию типов:
Обычно такая ситуация называется “ромбовидным наследованием”, и в ней нет ничего плохого— подобная структура встречается довольно часто. Проблема заключается в наследовании реализации. Если класс W содержит открытое поле goggin и у вас имеется ссылка на объект типа Z с именем zref, то чему будет соответствовать ссылка zref.goggin? Будет ли она представлять собой копию goggin из класса X, или из класса Y, или же X и Y будут использовать одну копию goggin, поскольку в действительности W входит в Z всего один раз, хотя Z одновременно является и X, и Y?
Чтобы избежать подобных проблем, в Java используется объектно-ориентированная модель с одиночным наследованием.
Одиночное наследование способствует правильному проектированию. Проблемы множественного наследования возникают из расширения классов при их реализации. Поэтому Java предоставляет возможность наследования контракта без связанной с ним реализации. Для этого вместо типа class используется тип interface.
Таким образом, интерфейсы входят в иерархию классов и наделяют Java возможностями множественного наследования.
Классы, расширяемые данным классом, и реализованные им интерфейсы совместно называются его супертипами; с точки зрения супертипов, новый класс является подтипом. В понятие “полного типа” нового класса входят все его супертипы, поэтому ссылка на объект класса может использоваться полиморфно— то есть всюду, где должна находиться ссылка на объект любого из супертипов (класса или интерфейса). Определения интерфейсов создают имена типов, подобно тому как это происходит с именами классов; вы можете использовать имя интерфейса в качестве имени переменной и присвоить ей любой объект, реализующий данный интерфейс.
4.3. Расширение интерфейсов
Интерфейсы также могут расширяться с помощью ключевого слова extended. В отличие от классов, допускается расширение интерфейсом сразу нескольких других интерфейсов:
interface Shimmer extends FloorWax, DessertTopping {
double amazingPrice();
}
Тип Shimmer расширяет FloorWax и DessertTopping; это значит, что все методы и константы, определенные в FloorWax и DessertTopping, являются составной частью его контракта, и к ним еще добавляется метод amazingPrice.
Если вы хотите, чтобы ваш класс реализовывал интерфейс и при этом расширял другой класс, то вам необходимо применить множественное наследование. Другими словами, у вас появляется класс, объекты которого могут использоваться там, где допускаются типы суперкласса и суперинтерфейса. Давайте рассмотрим следующее объявление:
interface W { }
interface X extends W { }
class Y implements W { }
class Z extends Y implements X { }
Ситуация отчасти напоминает знакомое нам “ромбовидное наследование”, но на этот раз нет никаких сомнений по поводу того, какие поля, X илиY, должны использоваться; у X нет никаких полей, поскольку это интерфейс, так что остается только Y. Диаграмма наследования будет выглядеть следующим образом:
W, X и Y могли бы быть интерфейсами, а Z— классом. Вот как бы это выглядело:
interface W { }
interface X extends W { }
interface Y extends W { }
class Z implements X, Y { }
Z оказывается единственным классом, входящим в данную иерархию.
У интерфейсов, в отличие от классов, нет единого корневого интерфейса (аналогичного классу Object), лежащего в основе всей иерархии. Несмотря на это, вы можете передать выражение любого из интерфейсных типов методу, получающему параметр типа Object, потому что объект должен принадлежать к какому-то классу, а все классы являются подклассами Object. Скажем, для приведенного выше примера допускается следующее присваивание переменной obj:
protected void twiddle(W wRef) {
Object obj = wRef;
// ...
}