Главная » Java » Наследование, контекст и сокрытие Java

0

с точки зрения кода внутреннего класса все имена, объявленные в пределах Внешнего класса, находятся в контексте - к ним позволено обращаться совершенно так же, как если бы те же инструкции внутреннего класса располагались в пределах внешнего класса. Члены внешнего класса способны перекрываться Одноименными полями, методами (и вложенными типами), принадлежащими Внутреннему классу. Подобная ситуация может возникать в двух случаях:

 

поле или метод объявлены во внутреннем классе

поле или метод унаследованы внутренним классом

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

Во втором случае использование простых имен не разрешается. Имя должно быть снабжено дополнительной ссылкой this либо super, если оно указывает на член текущего или базового внутреннего класса, либо квалификатором ИмяВнешнегоКласса.this, если ссылается на член внешнего класса. Причина введения такого требования связана с попыткой предотвратить возникновение Ситуаций, когда код, который, как кажется, должен делать одно, в действительности выполняет совершенно другое. Рассмотрим следующий фрагмент кода:

     

class Host{

      int x;

      class Helper extends Unknown {

            void increment() {x++;}

            // неверно!

      }

}

Метод increment должен, как предусмотрено, увеличить значение переменной Х в экземпляре внешнего класса Host. Объявление поля х, предположим, присутствует и в составе класса unknown и наследуется классом Неlреr. Унаследованное поле Х скрывает одноименное поле, принадлежащее контексту внешнего класса, поэтому, если бы приведенный выше код был допустим, он на самом деле означал бы увеличение на единицу значения поля х, унаследованного от unknown, и у читателя сложилось бы превратное впечатление о том, что произошло в действительности. Чтобы исключить подобные проблемы, компилятор требует снабдить переменную х явным квалификатором, который в состоянии ответить на вопрос, какое из двух полей х имеется в виду – this.х (поле текущего объекта) или Host.this.х (поле объекта внешнего класса).

Метод внутреннего класса перекрывает все перегруженные версии одноименного метода внешнего класса – даже в том случае, если в составе самого внутреннего класса нет соответствующих перегруженных вариантов метода. Например:

 

      class Outer {

            void print(){}

            void print(int val) {}

 

            class Inner {

                  void print(){}

                  void show() {

                        print();

                        Outer.this.print();

                        print(1); // ошибка: нет метода inner.print(int)

                  }

            }

      }

Объявление Inner.рrint перекрывает все версии Outer.рrint. Когда в Inner.show вызывается print(l), компилятор фиксирует, что в составе класса Inner нет объявления метода рrint с целочисленным параметром. Чтобы обратиться к варианту метода, объявленному во внешнем классе, следует явно задать квалификатор outer.this. Как обычно, от подобного сокрытия полей и методов проблем гораздо больше, нежели пользы.

Упражнение 5.1. Создайте версию класса BankAccount, в которой предусматривается возможность сохранения информации о десяти последних операциях, Выполненных с банковским счетом. Добавьте метод history, возвращающий объект класса History, метод next которого позволяет получать в хронологическом Порядке объекты Action с соответствующими данными об операциях и возвращает null, если список выполненных операций исчерпан. Следует ли объявить History в Виде вложенного класса? Если да, то какого – статического или нет?

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии