АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Название: МП(71) препод.(2531)

Читайте также:
  1. Название: «Идеологии»
  2. Народное название: крушина.
  3. Народное название: куриная слепота.

Название: ФА(35) препод.(4128) required->true

Следует помнить, что при вызове toString() обращение super всегда происходит к ближайшему суперклассу. Аналогично при вызове super() в конструкторе обращение происходит к соответствующему конструктору непосредственного суперкласса.

Основной вывод: выбор версии переопределенного метода производится на этапе выполнения кода.

Все методы Java являются виртуальными (ключевое слово virtual, как в C++, не используется).

Статические методы могут быть переопределены в подклассе, но не могут быть полиморфными, так как их вызов не затрагивает объекты. Их следует вызывать только с использованием имени класса.

Методы подставки

С пятой версии языка появилась возможность при переопределении методов указывать другой тип возвращаемого значения, в качестве которого можно использовать только типы, находящиеся ниже в иерархии наследования, чем исходный тип.

/* пример # 5: методы-подставки: CourseHelper.java:

BaseCourseHelper.java: RunnerCourse.java*/

package chapt04;

 

public class CourseHelper {

public Course getCourse(){

System. out. println("Course");

return new Course();

}

}

package chapt04;

 

public class BaseCourseHelper extends CourseHelper {

public BaseCourse getCourse(){

System. out. println("BaseCourse");

return new BaseCourse();

}

}

package chapt04;

 

public class RunnerCourse {

public static void main(String[] args) {

CourseHelper bch = new BaseCourseHelper();

Course course = bch.getCourse();

//BaseCourse course = bch.getCourse();//ошибка компиляции

System. out. println(bch.getCourse().id);

}

}

В данной ситуации при компиляции в подклассе BaseCourseHelper создаются два метода. При обращении к методу getCourse() версия метода определяется «ранним связыванием» без использования полиморфизма, но при выполнении вызывается метод-подставка. Обращение к полю производится по типу ссылки, возвращаемой методом getCourse(), то есть к полю класса Course.

Полиморфизм и расширяемость

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

В следующем примере приведение к базовому типу происходит в выражении:

Transport s1 = new Bus();

Transport
+
repair(): void
Bus
+
repair(): void
Tram
+
repair(): void

Transport s2 = new Tram();

Рис. 4.2. Пример реализации полиморфизма

Базовый класс Transport предоставляет общий интерфейс для своих подклассов. Порожденные классы Bus и Tram перекрывают эти определения для обеспечения уникального поведения.

/* пример # 5: полиморфизм: Transport.java: Bus.java: Tram.java:

RepairingCenter.java: Runner.java*/

package chapt04;

import java.util.Random;

 

class Transport {

public void repair() { /* пустая реализация */

}

}

class Bus extends Transport {

public void repair() {

System. out. println("отремонтирован АВТОБУС");

}

}

class Tram extends Transport {

public void repair() {

System. out. println("отремонтирован ТРАМВАЙ");

}

}

class RepairingFactory { //шаблон Factory

public Transport getClassFromFactory(int numMode) {

switch (new Random().nextInt(numMode)) {

case 0:

return new Bus();

case 1:

return new Tram();

default:

throw new IllegalArgumentException();

// assert false;

// return null;

/*

* if((int)(Math.random() * numMode)==0) return new Bus(); else

* return new Tram(); как альтернативный и не очень удачный

* вариант. Почему?

*/

}

}

}

public class Runner {

public static void main(String[] args) {

RepairingFactory rc = new RepairingFactory();

Transport[] box = new Transport[15];

 

for (int i = 0; i < box.length; i++)

/* заполнение массива единицами проверямого транспорта */

box[i] = rc.getClassFromFactory(2 );// 2 вида транспорта

for (Transport s: box)

s.repair(); // вызов полиморфного метода

}

}

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

Класс RepairingFactory содержит метод getClassFromFactory(int numMode), который возвращает ссылку на случайно выбранный объект подкласса класса Transport каждый раз, когда он вызывается. Приведение к базовому типу производится оператором return, который возвращает ссылку на Bus или Tram. Метод main() содержит массив из ссылок Transport, заполненный с помощью вызова getClassFromFactory(). На этом этапе известно, что имеется некоторое множество ссылок на объекты базового типа и ничего больше (не больше, чем знает компилятор). Kогда происходит перемещение по этому массиву, метод repair() вызывается для каждого случайным образом выбранного объекта.

Если понадобится в дальнейшем добавить в систему, например, класс TrolleyBus, то это потребует только переопределения метода repair() и добавления одной строки в код метода getClassFromFactory(), что делает систему легко расширяемой.

Статические методы и полиморфизм

Переопределение статических методов класса не имеет практического смысла, так как обращение к статическому атрибуту или методу осуществляется посредством задания имени класса, которому они принадлежат. К статическим методам принципы «позднего связывания» неприменимы. При использовании ссылки для доступа к статическому члену компилятор при выборе метода или поля учитывает тип ссылки, а не тип объекта, ей присвоенного.

/* пример # 6: поведение статического метода при «переопределении»: Runner.java */

package chapt04;

 

class Base {

public static void assign() {

System. out. println(

"метод assign() из Base");

}

}

class Sub extends Base {

public static void assign() {

System. out. println(

"метод assign() из Sub");

}

}

public class Runner {

public static void main(String[] args) {

Base ob1 = new Base();

Base ob2 = new Sub();

Sub ob3 = new Sub();

ob1. assign (); //некорректный вызов статичесого метода

ob2. assign (); //следует вызывать Base.assign();

ob3. assign ();

}

}

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


1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 |

Поиск по сайту:



Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.009 сек.)