
- •Кен Арнольд Джеймс Гослинг Дэвид Холмс Язык программирования 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
- •Приложение в Полезные таблицы
Какую работу нужно написать?
12.9. Классы Observer/Observable
Типы Observer/Observable предоставляют протокол, в соответствии с которым произвольное количество объектов-наблюдателей Observer получают уведомления о каких-либо изменениях или событиях, относящихся к произвольному количеству объектов Observable. Объект Observable производится от подкласса Observable, благодаря чему можно вести список объектов Observer, уведомляемых об изменениях в объекте Observable. Все объекты- “наблюдатели”, входящие в список, должны реализовывать интерфейс Observer. Когда с наблюдаемым объектом происходят изменения, заслужи вающие внимания, или случаются некоторые события, которые представляют интерес для Observer, вызывается метод notifyObservers объекта Observable, который обращается к методу update для каждого из объектов Observer. Метод update интерфейса Observable выглядит следующим образом:
public abstract void update(Observable obj, Object arg)
Метод вызывается, когда объект Observable должен сообщить наблюдателям об изменении или некотором событии. Параметр arg дает возможность передачи произвольного объекта, содержащего описание изменения или события в объекте Observer.
Механизм Observer/Observable проектировался с расчетом на универсальность. Каждый класс Observable сам определяет, когда и при каких обстоятельствах должен вызываться метод update объекта Observer.
Класс Observable реализует методы для ведения списка объектов Observer, для установки флага, сообщающего об изменении объекта, а также для вызова метода update любого из объектов Observer. Для ведения списка объектов Observer используются следующие методы:
public synchronized void addObserver(Observer o)
Добавляет аргумент o типа Observer к списку объектов-наблюдателей.
public synchronized void deleteObserver(Observer o)
Удаляет аргумент o типа Observer из списка объектов-наблюдателей.
public synchronized void deleteObservers()
Удаляет все объекты Observer из списка наблюдателей.
public synchronized int countObservers()
Возвращает количество объектов-наблюдателей.
Следующие методы извещают объекты Observer о произошедших изменениях:
public synchronized void notifyObservers(Object arg)
Уведомляет все объекты Observer о том, что с наблюдаемым объектом что-то произошло, после чего сбрасывает флаг изменения объекта. Для каждого объекта-наблюдателя, входящего в список, вызывается его метод update, первым параметром которого является объект Observable, а вторым— arg.
public void notifyObservers()
Эквивалентен notifyObservers(null).
Приведенный ниже пример показывает, как протокол Observer/Observable может применяться для наблюдения за пользователями, зарегистрированными в системе. Сначала определяется класс Users, расширяющий Observable:
import java.util.*;
public class Users extends Observable {
private Hashtable loggedIn = new Hashtable();
public void login(String name, String password)
throws BadUserException
{
// метод возбуждает исключение BadUserException
if (!passwordValid(name, password)
throw new BadUserException(name);
UserState state = new UserState(name);
loggedIn.put(name, state);
setChanged();
notifyObservers(state);
}
public void logout(UserState state) {
loggedIn.remove(state.name());
setChanged();
notifyObservers(state);
}
// ...
}
Объект Users содержит список активных пользователей и для каждого из них заводит объект UserState. Когда кто-либо из пользователей входит в систему или прекращает работу, то всем объектам Observer передается его объект UserState. Метод notifyObservers рассылает сообщения наблюдателям лишь в случае изменения состояния наблюдаемого объекта, так что мы должны также вызвать метод setChanged для Users, иначе notifyObservers ничего не сделает. Кроме метода setChanged, существует еще два метода для работы с флагом изменения состояния: clearChanged помечает объект Observable как неизменявшийся, а hasChanged возвращает логическое значение флага.
Ниже показано, как может выглядеть реализация update для объекта Observer, постоянно следящего за составом зарегистрированных пользователей:
import java.util.*;
public class Eye implements Observer {
Users watching;
public Eye(Users users) {
watching = users;
watching.addObserver(this);
}
public void update(Observable users, Object whichState)
{
if (users != watching)
throw new IllegalArgumentException();
UserState state = (UserState)whichState;
if (watching.loggedIn(state)) // вход в систему
addUser(state); // внести в список
else
removeUser(state); // удалить из списка
}
}
Каждый объект Eye наблюдает за конкретным объектом Users. Когда пользователь входит в систему или прекращает работу, объект Eye извещается об этом, поскольку в его конструкторе вызывается метод addObserver для объекта User, в котором объект Eye указывается в качестве объекта-наблюдателя. При вызове метода update происходит проверка на правильность параметров и изменение выводимой информации в зависимости от того, вошел ли данный пользователь в систему или вышел.
Проверка того, что происходит с объектом UserState, в данном случае выполняется просто. Впрочем, ее можно избежать— для этого следует вместо самого объекта UserState передавать объект-оболочку, который описывает, что и с кем происходит. Такой вариант выглядит нагляднее и облегчает добавление новых возможностей без нарушения существующего программного кода.
Механизм Observer/Observable отчасти напоминает механизм wait/ notify для потоков, описанный на стр., однако он отличается большей гибкостью и меньшим количеством ограничений. Механизм потоков гарантирует, что синхронный доступ защитит программу от нежелательных эффектов многозадачности. Механизм наблюдения позволяет организовать между участниками любую связь, не зависящую от используемых потоков. В обоих механизмах предусмотрен поставщик информации (Observable и объект, вызывающий notify) и ее потребитель (Obs e rver и объект, вызывающий wait), однако они удовлетворяют различные потребности. Используйте wait/ notify, когда механизм должен учитывать специфику потоков, и Observer/ Observable для более общих случаев.
Упражнение 12.6
Создайте реализацию интерфейса Attributed, в которой механизм Observer/Observable используется для уведомления наблюдателей об изменениях, происходящих c объектами.