Объектные переменные суперкласса и динамическое управление методами — КиберПедия 

Археология об основании Рима: Новые раскопки проясняют и такой острый дискуссионный вопрос, как дата самого возникновения Рима...

Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...

Объектные переменные суперкласса и динамическое управление методами

2019-08-04 415
Объектные переменные суперкласса и динамическое управление методами 0.00 из 5.00 0 оценок
Заказать работу

В наследовании было бы мало пользы, если бы не одно важное и интересное свойство объектных переменных суперкласса. Они могут ссылаться на объекты подкласса! Напомним, что объектная переменная — это переменная, значением которой является ссылка на объект соответствующего класса, то есть фактически та переменная, которую мы отождествляем с объектом. Объектная переменная объявляется так же, как обычная переменная базового типа, с той лишь разницей, что в качестве типа переменной указывается имя класса. Создается же объект с помощью оператора new и конструктора класса. Сказанное означает, что ссылку на объект подкласса (объект, созданный конструктором подкласса) можно присвоить в качестве значения объектной переменной суперкласса (в качестве типа переменной указав имя суперкласса).

Важное ограничение состоит в том, что через объектную переменную суперкласса можно ссылаться только на те члены подкласса, которые наследуются из суперкласса или переопределяются в подклассе. Пример приведен в листинге 9.

Листинг 9. Объектная переменная суперкласса ссылается на объект подкласса

class ClassA{

double Re;

void set(double x){

Re=x;}

void show(){

System.out.println("Класс A:");

System.out.println("Поле Re: "+Re);}

}

class ClassB extends ClassA{

double Im;

void set(double x,double y){

Re=x;

Im=y;}

void show(){

System.out.println("Класс B:");

System.out.println("Поле Re: "+Re);

System.out.println("Поле Im: "+Im);}

}

class SuperRefs{

public static void main(String[] args){

ClassA objA;

ClassB objB=new ClassB();

objA=objB;

objB.set(1,5);

objB.show();

objA.set(-10);

objA.show();}

}

В данном случае описывается суперкласс ClassA, на основе которого создается подкласс ClassB. В суперклассе ClassA объявлено поле double Re и методы set() и show(). Метод show() не имеет аргументов и выводит сообщение с названием класса (буквы-идентификатора класса) и значением поля Re. Метод set() имеет один аргумент, который присваивается в качестве значения полю Re. Поле Re наследуется в классе ClassB. В этом классе также описывается поле double Im. Метод set() перегружается так, чтобы иметь два аргумента — значения полей Re и Im. Перегружается и метод show(), чтобы выводить на экран значения двух полей.

В главном методе программы командой ClassA objA объявляется объектная переменная objA класса ClassA. Командой ClassB objB=new ClassB() создается объект класса ClassB, и ссылка на этот объект присваивается в качестве значения объектной переменной objB класса ClassB. Затем командой objA=objB ссылка на тот же объект присваивается в качестве значения объектной переменной objA. Таким образом, в результате и объектная переменная objA, и объектная переменная objB ссылаются на один и тот же объект. То есть переменных две, а объект один. Тем не менее ссылка на объект через переменную objA является «ограниченной» — через нее можно обращаться не ко всем членам объекта класса ClassB.

Командой objB.set(1,5) полям Re и Im объекта присваиваются значения 1 и 5 соответственно. Командой objB.show() значения полей объекта выводятся на экран. Для этого вызывается версия метода show(), описанная в классе ClassB.

Командой objA.set(-10) меняется значение поля Re. Для этого вызывается версия метода set(), описанная в классе ClassA и наследуемая в классе ClassB. Вызвать через объектную переменную objA версию метода set() с двумя аргументами не получится — эта версия не описана в классе ClassB, поэтому через объектную переменную суперкласса версия метода недоступна. Однако командой objA. show() можно вызвать переопределенный в классе ClassB метод show(). Результат выполнения программы следующий:

Класс B:

Поле Re: 1.0

Поле Im: 5.0

Класс B:

Поле Re: -10.0

Поле Im: 5.0

Отметим также, что в силу отмеченных особенностей ссылки на объект подкласса через объектную переменную суперкласса через переменную objA можно обратиться к полю Re объекта подкласса, но нельзя обратиться к полю Im.

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

Динамическое управление методами базируется на том, что выбор варианта перегруженного метода определяется не типом объектной ссылки, а типом объекта, причем на этапе не компиляции, а выполнения программы. С подобной ситуацией мы встречались в предыдущем примере, когда при ссылке на метод show() через объектную переменную objA суперкласса ClassA вызывалась переопределенная версия метода из подкласса ClassB, то есть версия, описанная в классе объекта, а не в классе объектной переменной. Рассмотрим еще один пример, представленный в листинге 10.

Листинг 10. Динамическое управление методами

class A{

void show(){

System.out.println("Класс А");}

}

class B extends A{

void show(){

System.out.println("Класс В");}

}

class C extends A{

void show(){

System.out.println("Класс C");}

}

class Dispatch{

public static void main(String args[]){

A a=new A();

B b=new B();

C c=new C();

A ref;

ref=a;

ref.show();

ref=b;

ref.show();

ref=c;

ref.show();}

}

В программе описывается суперкласс A, на основе которого создаются два класса: B и C. На рис. 2 приведена общая иерархическая схема классов программы.

 

 

 


Рис. 2. Структура классов при наследовании

 

В классе A описан метод show(), действие которого сводится к выводу на экран сообщения Класс A. В каждом из классов B и C этот метод переопределяется. Версия метода show() из класса B выводит сообщение Класс B, а версия этого же метода из класса C — сообщение Класс C.

В главном методе программы создаются объекты a, b и c соответственно классов A, B и C, а также объявляется объектная переменная ref класса A. Далее этой объектной переменной последовательно в качестве значений присваиваются ссылки на объекты a, b и c (командами ref=a, ref=b и ref=c). Поскольку класс A является суперклассом и для класса B, и для класса C, данные операции возможны. Причем после каждого такого присваивания через объектную переменную ref командой ref.show() вызывается метод show(). Результат выполнения программы имеет вид:

Класс А

Класс В

Класс C

Мы видим, что хотя формально во всех трех случаях команда вызова метода show() одна и та же (команда ref.show()), результат разный в зависимости от того, на какой объект в данный момент ссылается объектная переменная ref.

 

Абстрактные классы

В Java существуют такие понятия, как абстрактный метод и абстрактный класс. Под абстрактным методом подразумевают метод, тело которого в классе не объявлено, а есть только сигнатура (тип результата, имя и список аргументов). Перед таким абстрактным методом указывается идентификатор abstract, а заканчивается описание сигнатуры метода в классе традиционно — точкой с запятой.

Класс, который содержит хотя бы один абстрактный метод, называется абстрактным. Описание абстрактного класса начинается с ключевого слова abstract. Абстрактный класс в силу очевидных причин не может использоваться для создания объектов. Поэтому абстрактные классы являются суперклассами для подклассов. При этом в подклассе абстрактные методы абстрактного суперкласса должны быть определены в явном виде (иначе подкласс тоже будет абстрактным). Пример использования абстрактного класса приведен в листинге 11.

Листинг 11. Абстрактный класс

// Абстрактный суперкласс:

abstract class A{

// Абстрактный метод:

abstract void callme();

// Неабстрактный метод:

void callmetoo(){

System.out.println("Второй метод");}

}

// Подкласс:

class B extends A{

// Определение наследуемого абстрактного метода:

void callme(){

System.out.println("Первый метод");}

}

class AbstDemo{

public static void main(String args[]){

// Объект подкласса:

B obj=new B();

obj.callme();

obj.callmetoo();}

}

Пример достаточно простой: описывается абстрактный суперкласс A, на основе которого затем создается подкласс B. Суперкласс A содержит абстрактный метод call() и обычный (неабстрактный) метод callmetoo(). Оба метод наследуются в классе B. Но поскольку метод call() абстрактный, то он описан в классе B.

Методом call() выводится сообщение Первый метод, а методом callmetoo() — сообщение Второй метод. В главном методе программы создается объект подкласса и последовательно вызываются оба метода. В результате получаем сообщения:

Первый метод

Второй метод

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

Отметим еще одно немаловажное обстоятельство, которое касается наследования вообще. В некоторых случаях необходимо защитить метод от возможного переопределения в подклассе. Для этого при описании метода в его сигнатуре указывается ключевое слово final. Если это ключевое слово включить в сигнатуру класса, этот класс будет защищен от наследования — на его основе нельзя будет создать подкласс. Третий способ использования ключевого слова final касается описания полей (переменных). В этом случае оно означает запрет на изменение значения поля, то есть фактически означает определение константы.

 


Поделиться с друзьями:

Семя – орган полового размножения и расселения растений: наружи у семян имеется плотный покров – кожура...

Автоматическое растормаживание колес: Тормозные устройства колес предназначены для уменьше­ния длины пробега и улучшения маневрирования ВС при...

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

Историки об Елизавете Петровне: Елизавета попала между двумя встречными культурными течениями, воспитывалась среди новых европейских веяний и преданий...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.035 с.