русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Systems.out.println(Child.a) Systems.out.println(Parent.a)


Дата добавления: 2015-06-12; просмотров: 561; Нарушение авторских прав


А его результат сомнений уже не вызывает: 3 2

Можно привести следующее пояснение. Статическое поле принад­лежит классу, а не объекту В результате появление классов-наследников со скрывающими (hiding) объявлениями никак не сказывается на работе с исходным полем. Компилятор всегда может определить, через ссылку какого типа происходит обращение к нему.

Обратите внимание на следующий пример:

class Parent { static int а; }

class Child extends Parent { }

Каков будет результат следующих строк?

Chlld.a=10; Parent.a=5; System.out.println(Child.а);

В этом примере поле а не было скрыто и передалось по наследству классу Child. Однако результат показывает, что это все же одно поле: 5

Несмотря на то, что к полю класса идут обращения через разные *^ассы, переменная всего одна. Итак, наследники могут объявлять поля с именами, совпадающими ^ родительскими полями. Такие объявления называют скрывающими.

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

Методы

Рассмотрим случай переопределения (overriding) методов:

class Parent {public intgetValueO { return 0;

} } class Child extends Parent {public int getValueO { return 1;} }

И строки, демонстрирующие работу с этими методами:

Child с = new Chrld();

System.out.println(c.getValue());

Parent p = с;

System.out.println(p.getValue());

Результатом будет: 1

Можно видеть, что родительский метод полностью перекрыт, значе­ние 0 никак нельзя получить через ссылку, указывающую на объект класса Child. В этом ключевая особенность полиморфизма — наследники могут изменять родительское поведение, даже если обращение к ним произво­дится по ссылке родительского типа. Напомним, что, хотя старый метод снаружи уже недоступен, внутри класса-наследника к нему все же можно обратиться с помощью super.



Рассмотрим более сложный пример:

class Parent {

public int getValueO {

return 0; }

public void printO {

System.out. println(getValue()); } }

class Child extends Parent {

public int getValueO { return 1;} }

Что появится на консоли после выполнения следующих строк?

Parent р = new Child(); p.printO;

С помощью ссылки типа Parent вызывается метод print(), объявлен­ный в классе Parent. Из этого метода делается обращение к getValue(), которое в классе Parent возвращает 0. Но компилятор уже не может пред­сказать, к динамическому методу какого класса произойдет обращение во время работы программы. Это определяет виртуальная машина на основе объекта, на который указывает ссылка. И раз этот объект порожден от Child, то существует лишь один метод getValue().

Результатом работы примера будет: 1

Данный пример демонстрирует, что переопределение методов долж­но производиться с осторожностью. Если слишком сильно изменить логи­ку их работы, нарушить принятые соглашения (например, начать возвра­щать null в качестве значения ссылочного типа, если родительский метод такого не допускал), это может привести к сбоям в работе родительского класса, а значит, объекта наследника. Более того, существуют и некоторые обязательные ограничения.

Вспомним, что заголовок метода состоит из модификаторов, воз­вращаемого значения, сигнатуры и throws-выражения. Сигнатура (Имя и набор аргументов) остается неизменной, если говорить о пере­определении. Возвращаемое значение также не может меняться, и начало это приведет к появлению двух разных методов с одинаковыми сиг­натурами.

Рассмотрим модификаторы доступа.

class Parent {

protected int getValue() { return 0;

} }

class Child extends Parent {

/* ??? 7 protected Int getValue() { return 1;

} }

Пусть родительский метод был объявлен как protected. Понято, что метод наследника можно оставить с таким же уровнем доступа, но можно ли его расширить (public), или сузить (доступ по умолчанию)? Несколько строк для проверки:

Parent р = new Child(); p.getValueO;

Обращение к методу осуществляется с помощью ссылки типа Parent. Именно компилятор выполняет проверку уровня доступа, и он будет ори­ентироваться на родительский класс. Но ссылка-то указывает на объект, порожденный от Child, и по правилам полиморфизма исполняться будет метод именно этого класса. А значит, доступ к переопределенному методу не может быть более ограниченным, чем к исходному Итак, методы с до­ступом по умолчанию можно переопределять с таким же доступом, либо protected или public, Protected-методы переопределяются такими же, или public, а для public менять модификатор доступа и вовсе нельзя.

Что касается private-методов, то они определены только внутри класса, снаружи не видны, а потому наследники могут без ограничений объявлять методы с такими же сигнатурами и произвольными возвраща­емыми значениями, модификаторами доступа и т.д.

Аналогичные ограничения накладываются и на throws-выражен не, которое будет рассмотрено в следующих лекциях.

Если абстрактный метод переопределяется неабстрактным, то гово­рят, что он его реализовал (implements). Как ни странно, абстрактный ме­тод может переопределить другой абстрактный, или даже неабстрактный, метод. В первом случае такое действие может иметь смысл только при из­менении модификатора доступа (расширении), либо throws-выражения. Во втором случае полностью утрачивается старая реализация метода, что может потребоваться в особенных случаях.

Перейдем к статическим методам. Рассмотрим пример:

class Parent {

static public int getValue() { return 0;

} }

class Child extends Parent { static public int getValue() { return 1;

} }

И строки, демонстрирующие работу с этими методами:

Child с = new ChildO;

System.out.println(c.getValue());

Табл. 8.1. Взаимосвязь типа переменной и типов ее возможных значений.


Parent p = c;

System.out.println(p.getValue());

Аналогично случаю со статическими переменными, вспоминаем ал­горитм обработки компилятором таких обращений к статическим элемен­там и получаем, что код эквивалентен следующим строкам:

System.out.println(Child.getValue()); System.out.println(Parent.getValue());

Результатом будет:

1 О

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

Статические методы не могут перекрывать обычные, и наоборот.



<== предыдущая лекция | следующая лекция ==>
Полиморфизм | Полиморфизм и объекты


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.451 сек.