Доступ к унаследованным членам
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

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

Пример 25.

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);

}

}

Вот как выглядит результат работы программы:

Extend.show: ExtendStr

Extend.show: ExtendStr

sup . str : SuperStr

ext . str : ExtendStr

Существует только один объект, но две переменные, ссылающиеся на него: одна относится к типу SuperShow (базовому классу), а другая – к ExtendShow (фактическому классу). Что касается метода 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 для доступа к ним – методы переопределяются, но не скрываются.

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

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

Дата: 2019-02-19, просмотров: 211.