Local inner class (Локальный класс) - это вложенный класс, который может быть декларирован в любом блоке, в котором разрешается декларировать переменные. Как и простые внутренние классы (Member inner class) локальные классы имеют имена и могут использоваться многократно. Как и анонимные классы, они имеют окружающий их экземпляр только тогда, когда применяются в нестатическом контексте.
Локальные классы имеют следующие особенности:
● Видны только в пределах блока, в котором объявлены;
● Не могут быть объявлены как private/public/protected или static;
● Не могут иметь внутри себя статических объявлений (полей, методов, классов);
● Имеют доступ к полям и методам обрамляющего класса;
● Могут обращаться к локальным переменным и параметрам метода, если они объявлены с модификатором final.
Что такое «анонимные классы»? Где они применяются?
Это вложенный локальный класс без имени, который разрешено декларировать в любом месте обрамляющего класса, разрешающем размещение выражений. Создание экземпляра анонимного класса происходит одновременно с его объявлением. В зависимости от местоположения анонимный класс ведет себя как статический либо как нестатический вложенный класс - в нестатическом контексте появляется окружающий его экземпляр.
Анонимные классы имеют несколько ограничений:
● Их использование разрешено только в одном месте программы - месте его создания;
● Применение возможно только в том случае, если после порождения экземпляра нет необходимости на него ссылаться;
● Реализует лишь методы своего интерфейса или суперкласса, т.е. не может объявлять каких-либо новых методов, так как для доступа к ним нет поименованного типа.
Анонимные классы обычно применяются для:
● создания объекта функции (function object), например реализация интерфейса Comparator;
● создания объекта процесса (process object), такого как экземпляры классов Thread, Runnable и подобных;
● в статическом методе генерации;
● инициализации открытого статического поля final, которое соответствует сложному перечислению типов, когда для каждого экземпляра в перечислении требуется отдельный подкласс.
Каким образом из вложенного класса получить доступ к полю внешнего класса?
Статический вложенный класс имеет прямой доступ только к статическим полям обрамляющего класса.
Простой внутренний класс, может обратиться к любому полю внешнего класса напрямую. В случае, если у вложенного класса уже существует поле с таким же литералом, то обращаться к такому полю следует через ссылку на его экземпляр. Например: Outer.this.field.
13. Блоки инициализации.
Блоки инициализации представляют собой код, заключенный в фигурные скобки и размещаемый внутри класса вне объявления методов или конструкторов.
Существуют статические и нестатические блоки инициализации.
Блок инициализации выполняется перед инициализацией класса загрузчиком классов или созданием объекта класса с помощью конструктора.
Несколько блоков инициализации выполняются в порядке следования в коде класса.
Блок инициализации способен генерировать исключения, если их объявления перечислены в throws всех конструкторов класса.
Блок инициализации возможно создать и в анонимном классе.
Для чего в Java используются статические блоки инициализации?
Статические блоки инициализация используются для выполнения кода, который должен выполняться один раз при инициализации класса загрузчиком классов, в момент предшествующий созданию объектов этого класса при помощи конструктора. Такой блок (в отличие от нестатических, принадлежащих конкретном объекту класса) принадлежит только самому классу (объекту метакласса Class).
Что произойдет, если в блоке инициализации возникнет исключительная ситуация?
Для нестатических блоков инициализации, если выбрасывание исключения прописано явным образом требуется, чтобы объявления этих исключений были перечислены в throws всех конструкторов класса. Иначе будет ошибка компиляции. Для статического блока выбрасывание исключения в явном виде, приводит к ошибке компиляции.
В остальных случаях, взаимодействие с исключениями будет проходить так же как и в любом другом месте. Класс не будет инициализирован, если ошибка происходит в статическом блоке и объект класса не будет создан, если ошибка возникает в нестатическом блоке.
Какое исключение выбрасывается при возникновении ошибки в блоке инициализации класса?
Если возникшее исключение - наследник RuntimeException:
● для статических блоков инициализации будет выброшено java.lang.ExceptionInInitializerError;
● для нестатических будет проброшено исключение-источник.
Если возникшее исключение - наследник Error, то в обоих случаях будет выброшено java.lang.Error. Исключение: java.lang.ThreadDeath - смерть потока. В этом случае никакое исключение выброшено не будет.
14. Порядок вызова конструкторов и блоков инициализации с учётом иерархии классов.
Сначала вызываются все статические блоки в очередности от первого статического блока корневого предка и выше по цепочке иерархии до статических блоков самого класса.
Затем вызываются нестатические блоки инициализации корневого предка, конструктор корневого предка и так далее вплоть до нестатических блоков и конструктора самого класса.
Parent static block(s) → Child static block(s) → Grandchild static block(s)
→ Parent non-static block(s) → Parent constructor →
→ Child non-static block(s) → Child constructor →
→ Grandchild non-static block(s) → Grandchild constructor
15. Перегрузка и переопределение статических и нестатических методов.