вторник, 9 августа 2011 г.

Том 2. Глава 13. Аннотации.

"Аннотации - это дескрипторы, которые включаются в исходный текст для обработки специальными инструментами. Компилятор может обрабатывать данные дескрипторы на уровне исходного кода либо включать их в файлы классов."

"Для того, чтобы воспользоваться аннотациями, необходимо включить их в состав кода, выбрать инструмент обработки (processing tool) и применить его к программе. На момент написания данной главы стандартные инструменты обработки, пригодные для применения в промышленных масштабах, ещё не были разработаны."


Интересно, как изменилась ситуация за 6 лет...

"... стандартный обработчик аннотаций apt, входящий в состав JDK."

"В языке Java аннотации используются в роли модификаторов и размещаются перед пунктами, которые они помечают. Перед именем аннотации указывается символ @ ."


"Каждая аннотация должна быть определена посредством интерфейса аннотации. Методы интерфейса соответствуют элементам аннотации."

"Декларация @interface создаёт реальный Java-интерфейс. Инструменты, обрабатывающие аннотации, получают объекты, которые реализуют интерфейс аннотации."

"Аннотации @Target и @Retention представляют собой метааннотации. Они помечают обычные аннотации."


Вот так... Аннотации помечают код и являются метаданными, а метааннотации помечают аннотации и являются метаметаданными. :)

четверг, 4 августа 2011 г.

Глава 11. Исключения и отладка

“В подобной ситуации необходимо сделать по крайней мере три вещи:
Сообщить пользователю об обнаруженной ошибке.
Сохранить все результаты его работы.
Дать ему возможность аккуратно завершить работу программы.”

“Предназначение механизма обработки исключительной ситуаций - передать данные из того места, где возник сбой, обработчику ошибок, который может справиться с ними.”

“... передать данные”. Вот интересно мне, можно ли передать аргументы метода, в котором произошёл сбой, как-нибудь по-простому.

“ … язык Java в каждом методе предусматривает альтернативный выход, которым следует воспользоваться, если задачу невозможно выполнить до конца. В данной ситуации метод не станет возвращать значение, а возбудит (throw) объект, инкапсулирующий информацию об ошибке. Обратите внимание на то, что выход из метода выполняется незамедлительно. Более того, возобновить выполнение кода, вызвавшего данный метод, невозможно.”
Не очень понятно. “... возобновить выполнение кода, вызвавшего данный метод, невозможно.” Почему? Обработал ошибку - и запускай следующий метод.

“В языке Java объект исключительной ситуации всегда является экземпляром класса, производного от класса Throwable.”

“Иерархия Error описывает внутренние ошибки и ситуации, связанные с исчерпанием ресурсов в системе поддержки выполнения программ на языке Java. Ни один объект этого типа самому возбудить невозможно. Если возникла внутренняя ошибка, то … программист может сделать немногое.”

“Исключительные ситуации типа RuntimeException возникают вследствие ошибок программирования. Все другие исключительные ситуации являются следствием непредвиденного стечения обстоятельств.”

“Правило “Если возникла исключительная ситуация RuntimeException, то это - ваша вина” выполняется практически всегда.”

“В спецификации языка Java любая исключительная ситуация, производная от класса Error или RuntimeError, называется “неконтролируемой” (unchecked). Все остальные исключительные ситуации называются “контролируемыми” (checked).”

RuntimeError ?.. Это что такое? Опечатка?
Контролируемые, неконтролируемые... Не до конца понятно пока. Как-то хочется думать, что контролируемые - это те, которые можно предвидеть и программно предотвратить, например, проконтролировать правильность аргументов, а вот некотролируемые - это те, которые я даже если предвижу, то не могу с ними ничего поделать. А из текста получается наоборот...

“... метод не только сообщает компилятору, какие значения он может возвращать, но и предсказывает, какие ошибки могут возникнуть”.

“... внутренние ошибки … , производные от класса Error, объявлять не нужно. Аналогично не нужно объявлять неконтролируемые исключительные ситуации, производные от класса RuntimeException.”

"Неконтролируемые исключения либо находятся вне вашей компетенции (класс Error), либо являются следствием логических ошибок, которые не следовало допускать (класс RuntimeException)".

"Метод подкласса не может генерировать более общие исключения, чем замещаемый им метод суперкласса. В частности, если метод суперкласса вообще не генерирует контролируемые исключения, то и подкласс этого сделать не может."

пятница, 29 июля 2011 г.

Глава 5. Наследование.

"Поскольку конструктор подкласса не имеет доступа к закрытым полям суперкласса, он должен инициализировать их, вызывая другой конструктор с помощью ключевого слова super. Вызов, содержащий обращение super, должен быть первым оператором в конструкторе подкласса."

"Способность переменной ссылаться на объекты, имеющие разные фактические типы, называется полиморфизмом. Автоматический выбор нужного метода во время выполнения программы называется динамическим связыванием (dynamic binding)."

Метод equals()

"Метод equals() класса Object проверяет, эквивалентны ли два объекта. Однако в ряде случаев эквивалентными должны считаться объекты одного типа, имеющие одинаковые состояния."
"Чтобы объекты были эквивалентны, они как минимум должны быть объектами одного и того же класса."
[А как же с наследованием? Могут же быть эквивалентными объект класса-родителя и объект класса-наследника.]
"Определяя метод equals() для подкласса, надо сначала вызвать тот же метод суперкласса. Если проверка даст отрицательный результат, объекты не могут быть идентичными." [Возник такой вопрос. Почему при обращении из метода объекта-наследника к методу обекта-родителя, ссылка this в этом методе ссылается на объект-наследник ?] [Ссылка super, получается, работает как фильтр, отсекая всё неродительское. Другого объекта, на который ссылалась бы ссылка super, не существует. Это всё тот же наш текущий объект.]

суббота, 16 июля 2011 г.

Внутренние классы

"Закрытыми могут быть только внутренние классы. Обычные классы должны быть либо общедоступными, либо допускать обращение из того же пакета."
"В определении внутреннего класса ссылка [на внешний класс] явным образом не присутствует."
"Ссылка на объект внешнего класса задаётся в конструкторе."
"Если во внутреннем классе определены конструкторы, компилятор модифицирует их, добавляя параметр, выполняющий роль ссылки на внешний класс."


Итак, каждый экземпляр внутреннего класса обладает неявной ссылкой на экземпляр внешнего класса, с помощью которой получает доступ ко всем без исключения полям и методам этого внешнего объекта. Если логику управления состоянием внешнего объекта можно сконцентрировать в одном месте, то удобно использовать для этого именно внутренние классы.

"Выражение ВнешнийКласс.this означает ссылку на внешний класс."
"Конструктор внутреннего класса:
объектВнешнегоКласса.new ВнутреннийКласс (параметры)."
Ссылка на внутренний класс в области видимости внешнего класса: ВнешнийКласс.ВнутреннийКласс.

"... обработку внутренних классов осуществляет компилятор, а не виртуальная машина. Для их обозначения используется символ $, разделяющий имена внешних и внутренних классов ( TalkingClock$TimePrinter ); таким образом, для виртуальной машины внутренние классы неотличимы от внешних".

"Класс можно определить локально в отдельном методе".
"Локальные классы выгодно отличаются от обычных внутренних классов тем, что имеют доступ не только к полям своего внешнего класса, но и к локальным переменным."
" ... методы локального класса могут ссылаться только на локальные переменные, объявленные с помощью ключевого слова final (терминальные). Этим гарантируется, что локальная переменная и её копия, созданная внутри локального класса, всегда имеют одно и то же значение."

Синтаксис создания безымянного, или анонимного внутреннего класса:

new Интерфейс (параметры) { Свойства и методы внутреннего класса, реализующего Интерфейс };
или
new Класс (параметры) { Свойства и методы внутреннего класса, наследующего Класс};

"Если внутренний класс невелик и сводится всего к нескольким строчкам простого кода, можно сберечь время на указании типа, но сэкономленное время обернётся трудностями при чтении исходного текста программы."
"... только внутренние классы можно объявлять статическими. Статический внутренний класс ничем не отличается от любого другого внутреннего класса, за исключением того, что его объект не содержит ссылку на создавший его объект внешнего класса."
Proxy-классы

"[Proxy-классы] также часто называют классами-посредниками или заместителями."
"[Proxy-классы используются] для того, чтобы во время выполнения программы создавать новые классы, реализующие заданные интерфейсы. Proxy-классы необходимы, если на этапе компиляции программист ещё не знает, какие интерфейсы ему следует реализовать. ... Используя эту концепцию, часто удаётся избежать механической генерации и компиляции кода заглушек."
Создавать классы во время выполнения программы... Насколько я знаю, это можно делать с помощью механизма отражения.
Программист не знает, какие интерфейсы реализовывать... Интерфейсы из заданных интерфейсов? А как программист узнаёт, какие интерфейсы нужно реализовать? Нужно подготовить все реализации, а потом по каким-то условиям использовать некоторые из них? Для реализованных интерфейсов не нужно создавать заглушки, так?
Пока не очень понятно. Буду разбираться.

"Proxy-класс может создавать во время выполнения программы совершенно новые классы и реализует интерфейсы, которые указывает программист. В частности, в proxy-классе содержатся следующие методы:
- Все методы, которые требуют указанные интерфейсы.
- Все методы, определённые в классе Object.
Однако определить новый код для этих методов в ходе выполнения программы нельзя.
[Это для случаев, когда разные интерфейсы определяют методы с одинаковой сигнатурой ?] Вместо этого программист должен предоставить обработчик вызовов (invocation handler), представляющий собой объект, реализующий интерфейс InvocationHandler. В этом интерфейсе объявлен единственный метод:
Object invoke (Object proxy, Method method, Object[] args)
[Предполагаемый алгоритм: в proxy ищется метод, соответствующий сигнатуре, составленной из method и args, и выполняется. А что возвращается? Что это за Object? Если метод что-то возвращает, то понятно, а если метод void ?]"
"При вызове какого-либо метода из proxy-объекта автоматически вызывается метод invoke() обработчика вызовов.
[А как он автоматически вызывается?]"

"Чтобы создать proxy-объект, используется метод newProxyInstance() класса Proxy. Этот метод получает три параметра: 1) загрузчик класса (class loader); 2) массив объектов класса Class - по одному для каждого интерфейса, подлежащего реализации; 3) обработчик вызовов."


Тут тоже пока непонятно. Для того, чтобы использовать обработчик, нужно передать методу invoke() proxy-объект, но для того, чтобы создать этот proxy-объект, нужен обработчик...
Если proxy-объект - это аргумент метода invoke(), то этим подразумевается, что один и тот же обработчик вызовов можно использовать с разными proxy-объектами. Но для создания proxy-объекта нужно передать только один обработчик, т.е. есть какая-то жёсткая привязка. Какое-о противоречие.

"Proxy можно использовать для достижения следующих целей:
1) Переадресовывать вызовы методов на удалённый сервер.
2) Устанавливать связь между событиями пользовательского интерфейса и определёнными действиями, выполняемыми про работе программы.
3) Отслеживать вызовы методов при отладке."


"... proxy-классы создаются во время выполнения программы."

"Во всех proxy-классах переопределяются методы toString(), equals() и hashCode() класса Object. Эти методы лишь вызывают метод invoke(), принадлежащий обработчику событий. Другие методы класса Object не переопределяются."

"Для конкретного загрузчика классов и заданного набота интерфейсов может существовать только один proxy-класс."


"... все интерфейсы, которые реализуются proxy-классом, в объявлении которых не указан модификатор public, и сам proxy-класс должны принадлежать одному пакету."

[Имеются ввиду интерфейсы методов, правильно? Ведь список интерфейсов мы получаем от объектов, методы которых реализует proxy-объект. Таким образом, нужно анализировать взаимную видимость объектов. "Интерфейс принадлежит пакету" - это означает "класс, содержащий метод, которому соответствует интерфейс, принадлежит пакету" ?]

четверг, 14 июля 2011 г.

с. 262 (Черновик) Внутренние классы

"В языке C++ есть вложенные классы (nested)."
"Вложение представляет собой отношение между классами, а не между объектами. Объект [родительского] класса не содержит подобъектов [вложенных классов]."
А разве с внутренними классами в Java не так же? Разве родительский объект должен содержать объекты его внутренних классов?
-----
"У вложения классов есть два преимущества: управление именами (name control) и управление доступом (access control)."
"В языке Java ... управление именами осуществляют пакеты."
Методы родительского класса имеют доступ к полям и методам вложенного класса, но не наоборот.
-----
"... внутренние классы в языке Java имеют ещё одно достоинство, которое делает их более полезными, чем вложенные классы в языке C++. Объект внутреннего класса содержит неявную ссылку на объект внешнего класса, который создал его. С помощью этой ссылки объект внутреннего класса получает доступ ко всем полям и методам внешнего объекта.
Эту дополнительную ссылку не имеют лишь статические внутренние классы. Именно они представляют собой полный аналог вложенных классов языка C++."

с. 261 (Черновик) Внутренние классы

"Внутренним (inner) называется класс, определённый внутри другого класса. Зачем он нужен? Назовём четыре причины.

  • Объект внутреннего класса имеет доступ к реализации объекта, который его создал, включая закрытые данные.
  • Внутренний класс можно скрыть от других классов того же пакета.
  • Безымянный (anonimous) внутренний класс удобен, если нужно на лету уточнить обратные вызовы.
  • Внутренние классы очень удобны при создании событийно-управляемых программ."
3-ий и 4-ый пункты пока туманны...

с. 260 (Черновик) Клонирование объектов

"Определяя метод clone, вы снижаете уровень безопасности программы. ... в общем случае нужно проверить, как работают методы clone в каждом классе, который расширяет ваш класс."
... и переопределить в соответствии с дополнительными полями.