"Закрытыми могут быть только внутренние классы. Обычные классы должны быть либо общедоступными, либо допускать обращение из того же пакета."
"В определении внутреннего класса ссылка [на внешний класс] явным образом не присутствует."
"Ссылка на объект внешнего класса задаётся в конструкторе."
"Если во внутреннем классе определены конструкторы, компилятор модифицирует их, добавляя параметр, выполняющий роль ссылки на внешний класс."
Итак, каждый экземпляр внутреннего класса обладает неявной ссылкой на экземпляр внешнего класса, с помощью которой получает доступ ко всем без исключения полям и методам этого внешнего объекта. Если логику управления состоянием внешнего объекта можно сконцентрировать в одном месте, то удобно использовать для этого именно внутренние классы.
"Выражение ВнешнийКласс.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-объект. Таким образом, нужно анализировать взаимную видимость объектов. "Интерфейс принадлежит пакету" - это означает "класс, содержащий метод, которому соответствует интерфейс, принадлежит пакету" ?]
Комментариев нет:
Отправить комментарий