|
||||||||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Название: МП(71) препод.(2531)
Название: ФА(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 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 (); } } В результате выполнения данного кода будет выведено: Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.011 сек.) |