На какой объект будет реально указывать ссылка во время выполнения, не всегда можно точно определить на этапе компиляции. Полиморфизм позволяет ссылке указывать на объекты разных типов в разное время во время выполнения. Ссылка супертипа демонстрирует полиморфное поведение, поскольку она может указывать на объекты своих подтипов.
Когда у объекта вызывается He-private-метод экземпляра, то реально выполняемое описание метода определяется одновременно и типом объекта во время выполнения, и сигнатурой метода. Динамический поиск метода — это основанный на типе объекта процесс определения того, какое описание метода обозначается данной сигнатурой метода во время выполнения. Однако вызов private-метода экземпляра не является полиморфным, поскольку вызов может произойти только внутри класса и ограничивается реализацией private-метода во время компиляции.
Иерархия наследования, изображенная на рис. 6.5, реализована в примере 6.14. Реализация метода draw() переопределена во всех подклассах класса Shape. Вызов метода draw() в двух циклах в строках (3) и (4) в примере 6.14 основывается на полиморфном поведении ссылок и динамическом поиске метода. В массиве shapes содержатся ссылки типа Shape (Фигура), обозначающие Circle (Окружность), Rectangle (Прямоугольник) и Square (Квадрат), как показано в строке (1). Во время выполнения динамический поиск находит реализацию метода draw(), которую надо выполнить на основании типа объектов, на которые указывают элементы массива. Такая же схема применяется и для случая с массивом drawables в строке (2), который содержит ссылки типа IDrawable, а им можно присвоить любой объект класса, который реализует интерфейс IDrawable. Первый цикл будет продолжать работать без изменений, если объекты нового подкласса класса Shape добавить в массив shapes. Если они не переопределяют метод draw(), будет выполнена унаследованная версия метода. Такое полиморфное поведение применимо к массиву drawables, в котором объекты подтипа с гарантией реализуют интерфейс IDrawable.
Полиморфизм и динамический поиск метода образуют мощную парадигму программирования, которая упрощает определения клиентов, содействует разделению объектов и поддерживает динамическую перенастройку связей между объектами во время выполнения.
Рис. 6.5. Полиморфные методы
Пример 6.14. Полиморфизм и динамический поиск метода
interface IDrawable {
void draw();
}
class Shape implements IDrawable {
public void draw() { System.out.println("Drawing a Shape."); }
}
class Circle extends Shape {
public void draw() { System.out.println("Drawing a Circle."); }
}
class Rectangle extends Shape {
public void draw() { System.out.println("Drawing a Rectangle."); }
}
class Square extends Rectangle {
public void draw() { System.out.println("Drawing a Square."); }
}
class Map implements IDrawable {
public void draw() { System.out.println("Drawing a Map."); }
}
public class PolymorphRefs {
public static void main(String[] args) {
Shape[] shapes = { new Circle(), new Rectangle(), new Square() }; // (1)
IDrawable[] drawables = { new Shape(), new Rectangle(), new Map() };// (2)
System.out.println("Draw shapes:");
for (int i = 0; i < shapes.length; i++) // (3)
shapes[i].draw();
System.out.println("Draw drawables:");
for (int i = 0; i < drawables.length; i++) // (4)
drawables[i].draw();
}
}Вывод программы:
Draw shapes:
Drawing a Circle.
Drawing a Rectangle.
Drawing a Square.
Draw drawables:
Drawing a Shape.
Drawing a Rectangle.
Drawing a Map.| Преобразование типов значений ссылок | Наследование в сравнении с агрегацией |