Археология об основании Рима: Новые раскопки проясняют и такой острый дискуссионный вопрос, как дата самого возникновения Рима...
Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...
Топ:
Установка замедленного коксования: Чем выше температура и ниже давление, тем место разрыва углеродной цепи всё больше смещается к её концу и значительно возрастает...
Эволюция кровеносной системы позвоночных животных: Биологическая эволюция – необратимый процесс исторического развития живой природы...
Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов...
Интересное:
Аура как энергетическое поле: многослойную ауру человека можно представить себе подобным...
Средства для ингаляционного наркоза: Наркоз наступает в результате вдыхания (ингаляции) средств, которое осуществляют или с помощью маски...
Искусственное повышение поверхности территории: Варианты искусственного повышения поверхности территории необходимо выбирать на основе анализа следующих характеристик защищаемой территории...
Дисциплины:
2019-08-04 | 415 |
5.00
из
|
Заказать работу |
|
|
В наследовании было бы мало пользы, если бы не одно важное и интересное свойство объектных переменных суперкласса. Они могут ссылаться на объекты подкласса! Напомним, что объектная переменная — это переменная, значением которой является ссылка на объект соответствующего класса, то есть фактически та переменная, которую мы отождествляем с объектом. Объектная переменная объявляется так же, как обычная переменная базового типа, с той лишь разницей, что в качестве типа переменной указывается имя класса. Создается же объект с помощью оператора 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 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!