Главная » Java » Доступ к унаследованным членам Java

0

Когда в теле метода содержится обращение к члену, переопределенному в производном классе, естественно задаться вопросом, какой именно член в действительности окажется доступен – объявленный в базовом классе или заново созданный в производном? Ответ зависит от того, к какой категории относится член класса, каким модификатором доступа он снабжен и как именно осуществляется обращение к нему.

Если вызывается метод посредством ссылки на объект, выбор одной из возможных альтернатив обусловливается фактическим классом объекта. Если же

осуществляется обращение к полю, в рассмотрение принимается объявленный тип ссылки. Следующий пример поможет нам разобраться, что к чему:

class SuperShow {

public String str = "SuperStr";

public void show() {

system.out.println("Super.show: " + str);

 

}

class ExtendShow extends SuperShow {

public String str = "ExtendStr";

public void show() {

 System.out.println("Extend.show: " + str);

 }

public static void main(String[] args) {

ExtendShow ext = new ExtendShow();

SuperShow sup = ext;

sup. show() ;

ext. show() ;

 system.out.println("sup.str = “ + sup.str);

system.out.println("ext.str = “ + ext.str);

 

}

}

Существуют только один объект, но две переменные, ссылающиеся на него: одна относится к типу SuperShow (базовому классу), а другая – к ExtendShow (фактическому классу). Вот как выглядит результат работы программы:

Extend.show: ExtendStr

 Extend.show: ExtendStr

 sup.str = SuperStr

 ext.str = ExtendStr

Что касается метода show, результат работы программы вполне предсказуем:

Выбор одного из двух перегруженных методов определяется фактическим классом объекта, а не типом переменной, ссылающейся на него. У нас есть единственный объект типа ExtendShow, и при обращении к методу show всегда вызывается именно тот show, который принадлежит ExtendShow, даже если ссылка На объект осуществляется через переменную базового типа SuperShow. Это происходит в любом случае – и когда обращение к show выполняется с помощью Внешнего вызова (как в примере), и при вызове show из тела другого метода.

При выборе одного из двух одноименных полей учитывается объявленный тип Ссылки на объект, а не тип самого объекта. Действительно, каждый объект класса ExtendShow обладает двумя полями типа String, названными str объявленное в классе SuperShow, скрыто тем, что определено в ExtendShow.

 

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

Внутри тела метода, такого как, скажем, show, ссылка на поле всегда указывает именно на то поле, которое объявлено в классе, где объявлен и сам Метод, либо на унаследованное поле, если соответствующее объявление поля в данном классе отсутствует. Поэтому в методе SuperShow. show ссылка на str указывает в действительности на SuperShow.str, а в ExtendShow.show – На

ExtendShow.str

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

Если методу передается ссылочный аргумент типа SuperShow, с помощью которого метод пытается обратиться к полю str, он всегда получит в действительности SuperShow. str – даже в том случае, когда за ссылкой SuperShow "скрывается" объект производного класса ExtendShow. Если в подобной ситуации было бы предусмотрено обращение к "равноценному" методу, который обеспечивает доступ к тому же полю str, компилятор гарантировал бы вызов метода, переопределенного в ExtendShow и возвращающего ExtendShow. str. "Капризное" поведение полей при их сокрытии, о котором мы рассказали, служит еще одним доводом в пользу повсеместного и активного применения приватных полей и открытых методов set и get для доступа к ним – методы переопределяются, но не скрываются.

Сокрытие полей формально позволено с той целью, чтобы разработчики существующих базовых классов могли свободно добавлять в них новые поля publiс и protected, не рискуя причинить вреда всем возможным "наследникам". Если бы язык запрещал использование одноименных полей в базовом и производных классах, добавление нового поля в существующий базовый класс оказывалось бы чревато проблемами, поскольку в некоем производном классе, возможно, уже объявлено поле с тем же именем.

Если модификация базового класса способна затронуть неопределенное число про из водных классов, вы как "генеральный конструктор" оказываетесь совершенно скованы, поскольку лишены возможности добавления в базовый класс полей publiс и protected. Блюстители показной чистоты могли бы поймать нас на слове, заявив, что, дескать, в классах следует использовать только Поля private и что никакой проблемы, собственно говоря, и нет, но мы в данном случае склонны к компромиссам – только нам с вами решать, что в конкретной ситуации хорошо, а что плохо.

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

По теме:

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