Чтение онлайн

на главную - закладки

Жанры

Философия Java3

Эккель Брюс

Шрифт:

Для всех методов Java используется механизм позднего связывания, если только метод не был объявлен как final (приватные методы являются final по умолчанию). Следовательно, вам не придется принимать решений относительно использования позднего связывания — оно осуществляется автоматически.

Зачем объявлять метод как final? Как уже было замечено в предыдущей главе, это запрещает переопределение соответствующего метода. Что еще важнее, это фактически «отключает» позднее связывание или, скорее, указывает компилятору на то, что позднее связывание не является необходимым. Поэтому для методов final компилятор генерирует чуть более эффективный код. Впрочем, в большинстве случаев влияние на производительность вашей программы незначительно, поэтому final лучше использовать в качестве продуманного элемента своего проекта, а не как средство улучшения производительности.

Получение нужного результата

Теперь, когда вы знаете, что связывание всех методов в Java осуществляется полиморфно, через позднее связывание, вы можете писать код для базового класса, не сомневаясь в том, что для всех производных классов он также будет работать верно. Другими словами, вы «посылаете сообщение объекту и позволяете ему решить, что следует делать дальше».

Классическим примером полиморфизма в ООП является пример с геометрическими фигурами. Он часто используется благодаря своей наглядности, но, к сожалению, некоторые новички начинают думать, что ООП подразумевает графическое программирование — а это, конечно же, неверно.

В примере с фигурами имеется базовый класс с именем Shape (фигура) и различные производные типы: Circle (окружность), Square (прямоугольник), Triangle (треугольник) и т. п. Выражения типа «окружность есть фигура» очевидны и не представляют трудностей для понимания. Взаимосвязи показаны на следующей диаграмме наследования:

Восходящее преобразование имеет место даже в такой простой команде: Shape s = new CircleO;

Здесь создается объект Circle, и полученная ссылка немедленно присваивается типу Shape. На первый взгляд это может показаться ошибкой (присвоение одного типа другому), но в действительности все правильно, потому что тип Circle (окружность) является типом Shape (фигура) посредством наследования. Компилятор принимает команду и не выдает сообщения об ошибке.

Предположим, вызывается один из методов базового класса (из тех, что были переопределены в производных классах):

s.drawO;

Опять можно подумать, что вызывается метод draw из класса Shape, раз имеется ссылка на объект Shape — как компилятор может сделать что-то другое? И все же будет вызван правильный метод Circle.draw, так как в программе используется позднее связывание (полиморфизм).

Следующий пример показывает несколько другой подход:

//: polymorph!sm/shape/Shapes java package polymorphism.shape;

public class Shape {

public void drawO {} public void eraseO {} } Hill'. polymorphism/shape/Circle java package polymorphism shape: import static net.mindview.util.Print.*,

public class Circle extends Shape {

public void drawO { printC'Circle.drawO"); } public void eraseO { printC'Circle.eraseO"). } } Hill-. polymorphism/shape/Square.java package polymorphism.shape: import static net.mindview.util Print *.

public class Square extends Shape {

public void drawO { printC'Square.drawO"), } _ Л

продолжение &

public void eraseO { printC'Square.eraseO"); } } ///.-

//• polymorphism/shape/Triangle java

package polymorphism.shape;

import static net mindview.util Print.*;

public class Triangle extends Shape {

public void drawO { printC'Triangle.drawO"). } public void eraseO { printC'Triangle eraseO"). } } Hill. polymorphism/shape/RandomShapeGenerator java II "Фабрика", случайным образом создающая объекты package polymorphism.shape; import java.util *;

public class RandomShapeGenerator {

private Random rand = new Random(47); public Shape next О {

switch(rand nextlnt(3)) { default-

case 0: return new CircleO; case 1: return new SquareO, case 2: return new TriangleO;

}

}

} Hill: polymorphism/Shapes.java II Polymorphism in Java, import polymorphism.shape.*;

public class Shapes {

private static RandomShapeGenerator gen =

new RandomShapeGeneratorO; public static void main(String[] args) { Shape[] s = new Shape[9]; II Заполняем массив фигурами: for(int i = 0, i < s.length; i++)

s[i] = gen nextO; II Полиморфные вызовы методов-for(Shape shp • s) shp.drawO,

}

} /* Output: Triangle.drawO Triangle.drawO Square drawO Triangle.drawO Square.drawO Triangle drawO Square drawO Triangle drawO Circle.drawO *///.-

Базовый класс Shape устанавливает общий интерфейс для всех классов, производных от Shape — то есть любую фигуру можно нарисовать (draw) и стереть (erase). Производные классы переопределяют этот интерфейс, чтобы реализовать уникальное поведение для каждой конкретной фигуры.

Класс RandomShapeGenerator — своего рода «фабрика», при каждом вызове метода next производящая ссылку на случайно выбираемый объект Shape. Заметьте, что восходящее преобразование выполняется в командах return, каждая из которых получает ссылку на объект Circle, Square или Triangle, а выдает ее за пределы next в виде возвращаемого типа Shape. Таким образом, при вызове этого метода вы не сможете определить конкретный тип объекта, поскольку всегда получаете просто Shape.

Метод main содержит массив ссылок на Shape, который заполняется последовательными вызовами RandomShapeGenerator.next. К этому моменту вам известно, что имеются объекты Shape, но вы не знаете об этих объектах ничего конкретного (так же, как и компилятор). Но если перебрать содержимое массива и вызвать draw для каждого его элемента, то, как по волшебству, произойдет верное, свойственное для определенного типа действие — в этом нетрудно убедиться, взглянув на результат работы программы.

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

Расширяемость

Теперь вернемся к программе Music.java. Благодаря полиморфизму вы можете добавить в нее сколько угодно новых типов, не изменяя метод tune. В хорошо спланированной ООП-программе большая часть ваших методов (или даже все методы) следуют модели метода tune, оперируя только с интерфейсом базового класса. Такая программа является расширяемой, поскольку в нее можно добавить дополнительную функциональность, определяя новые типы данных от общего базового класса. Методы, работающие на уровне интерфейса базового класса, совсем не нужно изменять, чтобы приспособить их к новым классам.

Поделиться:
Популярные книги

Чужое наследие

Кораблев Родион
3. Другая сторона
Фантастика:
боевая фантастика
8.47
рейтинг книги
Чужое наследие

Наследник, скрывающий свой Род

Тарс Элиан
2. Десять Принцев Российской Империи
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Наследник, скрывающий свой Род

Я снова князь. Книга XXIII

Дрейк Сириус
23. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я снова князь. Книга XXIII

Локки 5. Потомок бога

Решетов Евгений Валерьевич
5. Локки
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Локки 5. Потомок бога

Глубокий космос

Вайс Александр
9. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
космоопера
5.00
рейтинг книги
Глубокий космос

Надуй щеки!

Вишневский Сергей Викторович
1. Чеболь за партой
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Надуй щеки!

Московское золото и нежная попа комсомолки. Часть Пятая

Хренов Алексей
5. Летчик Леха
Фантастика:
попаданцы
5.00
рейтинг книги
Московское золото и нежная попа комсомолки. Часть Пятая

Дитя прибоя

Трофимов Ерофей
Дитя прибоя
Фантастика:
боевая фантастика
попаданцы
фэнтези
5.00
рейтинг книги
Дитя прибоя

Княжна попаданка. Последняя из рода

Семина Дия
1. Княжна попаданка. Магическая управа
Фантастика:
попаданцы
альтернативная история
историческое фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Княжна попаданка. Последняя из рода

Печать мастера

Лисина Александра
6. Гибрид
Фантастика:
попаданцы
технофэнтези
аниме
фэнтези
6.00
рейтинг книги
Печать мастера

Офицер Красной Армии

Поселягин Владимир Геннадьевич
2. Командир Красной Армии
Фантастика:
попаданцы
8.51
рейтинг книги
Офицер Красной Армии

Локки 6. Потомок бога

Решетов Евгений Валерьевич
6. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Локки 6. Потомок бога

На границе империй. Том 10. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 4

Барон запрещает правила

Ренгач Евгений
9. Закон сильного
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Барон запрещает правила