Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Динамическая диспетчеризация методов




Динамическая диспетчеризация методов

Хотя приведенные в предыдущем разделе примеры демонстрируют механизм переопределения методов, они не показывают всех возможностей. Действительно, если бы переопределение методов служило лишь для удобства работы с пространством имен, оно представляло бы только определенный теоретический интерес, но имело бы очень небольшое практическое значение. Однако это не так. Переопределение методов служит основой для одной из наиболее мощных концепций Java – динамической диспетчеризации методов. Динамическая диспетчеризация методов – механизм, посредством которого разрешение обращения к переопределенному методу осуществляется во время выполнения, а не во время компиляции.

Динамическая диспетчеризация методов важна потому, что именно с ее помощью Java реализует полиморфизм времени выполнения. Рассмотрение этой концепции начнем с повторной формулировки одного важного принципа: ссылочная переменная суперкласса может ссылаться на объект подкласса.

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

В следующем примере иллюстрируется динамическая диспетчеризация методов.

// Динамическая диспетчеризация методов

class A {

void callme() {

System. out. println(" Внутри метода callme класса A" );

}

}

class B extends A {

// переопределение метода callme()

void callme() {

System. out. println(" Внутри метода callme класса B" );

}

}

class C extends A {

// переопределение метода callme()

void callme() {

System. out. println(" Внутри метода callme класса C" );

}

}

class Dispatch {

public static void main(String args[]) {

A a = new A(); // объект типа A

B b = new B(); // объект типа B

C c = new C(); // объект типа C

A r; // получение ссылки типа A

r = a; // r ссылается на объект A

r. callme(); // вызов версии метода callme, определенной в A

r = b; // r ссылается на объект B

r. callme(); // вызов версии метода callme, определенной в B

r = c; // r ссылается на объект C

r. callme(); // вызов версии метода callme, определенной в C

}

}

Эта программа генерирует следующий вывод:

Внутри метода callme класса A

Внутри метода callme класса B

Внутри метода callme класса C

Эта программа создает один суперкласс A и два его подкласса: B и C. Подклассы B и C переопределяют метод callme(), объявленные в классе A. Внутри метода main() программа объявляет объекты типов A, B и C. Программа объявляет также ссылку типа A по имени r. Затем программа по очереди присваивает переменной r ссылку на каждый тип объекта и использует эту ссылку для вызова метода callme(). Как видно из вывода, выполняемая версия метода callme() определяется по типу объекта ссылки во время выполнения. Если бы выбор осуществлялся по типу ссылочной переменной, r, вывод отражал бы три обращения к методу callme() класса A.

Использование переопределения методов

Как уже было сказано, переопределенные методы позволяют Java поддерживать полиморфизм времени выполнения. Большое значение полиморфизма для объектно-ориентированного программирования обусловлено следующей причиной: он позволяет общему классу указывать методы, которые станут общими для всех его производных классов, в то же время позволяя подклассам определять конкретные реализации некоторых или всех этих методов. Переопределенные методы – еще один используемый в Java способ реализации аспекта полиморфизма под названием “один интерфейс, множество методов”.

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

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

Рассмотрим более реальный пример использования переопределения методов.

Следующая программа создает суперкласс Figure, который хранит размеры двумерного объекта. Она определяет также метод area(), который вычисляет площадь объекта. Программа создает два класса, производных от класса Figure: Rectangle и Triangle. Каждый из этих подклассов переопределяет метод area(), чтобы он возвращал соответственно площадь четырехугольника и треугольника.

// Применение полиморфизма времени выполнения.

class Figure {

double dim1;

double dim2;

Figure(double a, double b) {

dim1 = a;

dim2 = b;

}

double area() {

System. out. println(" Площадь фигуры не определена. " );

return 0;

}

}

class Rectangle extends Figure {

Rectangle(double a, double b) {

super(a, b);

}

// переопределение метода area для четырехугольника

double area() {

System. out. println(" В области четырехугольника. " );

BookNew_JAVA-7. indb 208 02. 06. 2007 1: 06: 55

Глава 8. Наследование 209

return dim1 * dim2;

}

}

class Triangle extends Figure {

Triangle(double a, double b) {

super(a, b);

}

// переопределение метода area для прямоугольного треугольника

double area() {

System. out. println(" В области треугольника. " );

return dim1 * dim2 / 2;

}

}

class FindAreas {

public static void main(String args[]) {

Figure f = new Figure(10, 10);

Rectangle r = new Rectangle(9, 5);

Triangle t = new Triangle(10, 8);

Figure figref;

figref = r;

System. out. println(" Площадь равна " + figref. area());

figref = t;

System. out. println(" Площадь равна " + figref. area());

figref = f;

System. out. println(" Площадь равна " + figref. area());

}

}

Эта программа создает следующий вывод:

В области четырехугольника.

Площадь равна 45

В области треугольника.

Площадь равна 40

Область фигуры не определена.

Площадь равна 0

Двойственный механизм наследования и полиморфизма времени выполнения позволяет определить единый интерфейс, используемый несколькими различными, но сходными типами объектов. В данном случае, если объект является производным от Figure, его площадь можно вычислять, вызывая метод area(). Интерфейс выполнения этой операции остается неизменным, независимо от типа фигуры.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...