Наследование и переопределение методов — КиберПедия 

Наброски и зарисовки растений, плодов, цветов: Освоить конструктивное построение структуры дерева через зарисовки отдельных деревьев, группы деревьев...

Папиллярные узоры пальцев рук - маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни...

Наследование и переопределение методов

2019-08-04 185
Наследование и переопределение методов 0.00 из 5.00 0 оценок
Заказать работу

Наследование и переопределение методов

Одним из фундаментальных механизмов, лежащих в основе любого объектно-ориентированного языка, в том числе Java, является наследование. Наследование позволяет одним объектам получать характеристики других объектов. Представим себе ситуацию, когда на основе уже существующего, проверенного и работающего кода нужно создать новую программу. Есть два пути решения этой задачи. Во-первых, можно скопировать уже существующий код в новый проект и внести необходимые изменения. Во-вторых, в новом проекте можно сделать ссылку на уже существующий код. Второй вариант во многих отношениях предпочтительнее, поскольку позволяет сэкономить время и усилия на создание нового кода и обеспечивает более высокую степень совместимости программ. Ведь если окажется, что базовый код необходимо доработать, то это достаточно сделать единожды: поскольку код инкапсулируется через ссылку, внесенные изменения вступят в силу автоматически во всех местах, где этот код используется.

Именно по этому принципу реализован механизм наследования. С практической точки зрения наследование позволяет одним объектам получать (наследовать) свойства других объектов. Реализуется наследование путем создания классов на основе уже существующих классов. При этом члены класса, на основе которого создается новый класс, с некоторыми оговорками, автоматически включаются в новый класс. Кроме того, в создаваемый класс можно добавлять новые члены. Согласно общепринятой терминологии, класс, на основе которого создается новый класс, называется суперклассом. Новый создаваемый на основе суперкласса класс называется подклассом.

Создание подкласса

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

Для реализации наследования в описании подкласса после имени класса указывается ключевое слово extends и имя суперкласса. Во всем остальном описание подкласса не отличается от описания обычного класса (то есть класса, который создается «с нуля»). Синтаксис описания подкласса имеет вид:

class A extends B{

// код

}

В данном случае подкласс A создается на основе суперкласса B. В результате подкласс A получает (наследует) открытые и защищенные члены класса B.

Обращаем внимание читателя, что в языке Java, в отличие от языка С++, отсутствует множественное наследование, то есть подкласс в Java может создаваться на основе только одного суперкласса. При этом в Java, как и в С++, существует многоуровневое наследование: подкласс, в свою очередь, может быть суперклассом для другого класса. Благодаря многоуровневому наследованию можно создавать целые цепочки связанных механизмом наследования классов. В листинге 1 приведен пример создания подкласса.

Листинг 1. Создание подкласса

class A{ // Суперкласс

int i,j;

void showij(){

System.out.println("Поля i и j: "+i+" и "+j);}

}

class B extends A{ // Подкласс

int k;

void showk(){

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

void sum(){

// Обращение к наследуемым полям:

System.out.println("Сумма i+j+k="+(i+j+k));}

}

class AB{

public static void main(String arg[]){

// Объект суперкласса:

A SuperObj=new A();

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

B SubObj=new B();

SuperObj.i=10;

SuperObj.j=20;

SuperObj.showij();

SubObj.i=7;

SubObj.j=8;

SubObj.k=9;

SubObj.showij();

SubObj.showk();

SubObj.sum();}

}

В программе описан суперкласс A, в котором объявлены два целочисленных поля i и j, а также метод showij() для отображения значений этих полей. На основе класса A создается класс B (подкласс суперкласса A). Непосредственно в теле класса B описано целочисленное поле k, а также методы showk() и sum() для вывода значения поля k и вычисления суммы полей i, j и k. Обращаем внимание, что хотя поля i и j непосредственно в классе B не описаны, в классе B о них известно, поскольку они наследуются этим классом (то есть у класса B имеются целочисленные поля i и j) и к ним можно обращаться.

В методе main() класса AB создаются два объекта: объект SuperObj суперкласса A и объект SubObj подкласса B. Полям i и j объекта SuperObj присваиваются значения 10 и 20 соответственно, после чего с помощью метода showij() значения полей выводятся на экран. Полям i, j и k объекта SubObj присваиваются целочисленные значения 7, 8 и 9. Методом showij() отображаются значения полей i и j, а значение поля k отображается с помощью метода showk(). Наконец, сумма полей вычисляется методом sum(). Результат выполнения программы следующий:

Поля i и j: 10 и 20

Поля i и j: 7 и 8

Поле k: 9

Сумма i+j+k=24

Другими словами, ситуация такая, как если бы поля i и j, а также метод showij() были описаны в классе B. Достигается такой эффект благодаря наследованию.

 

Конструкторы и наследование

Если суперкласс и подкласс используют конструкторы по умолчанию (то есть ни в суперклассе, ни в подклассе конструкторы не описаны), то процесс со здания объекта подкласса для программиста проходит обыденно — так же, как создание объекта обычного класса. Ситуация несколько меняется, если конструктору суперкласса необходимо передавать аргументы. Возникает проблема: поскольку при создании объекта подкласса сначала автоматически вызывается конструктор суперкласса, в этот конструктор как-то нужно передать аргументы, даже если непосредственно конструктор подкласса может без них обойтись.

Все это накладывает некоторые ограничения на способ описания конструктора подкласса. Формально эти ограничения сводятся к тому, что в конструкторе подкласса необходимо предусмотреть передачу аргументов конструктору суперкласса (разумеется, если такая передача аргументов вообще требуется).

Технически решение проблемы сводится к тому, что в программный код конструктора подкласса добавляется инструкция вызова конструктора суперкласса с указанием аргументов, которые ему передаются. Для этого используется ключевое слово super, после которого в круглых скобках указываются аргументы, передаваемые конструктору суперкласса. Инструкция вызова конструктора суперкласса указывается первой командой в теле конструктора подкласса. Таким образом, общий синтаксис объявления конструктора подкласса имеет следующий вид:

конструктор_подкласса(аргументы1){

super(аргументы2); // аргументы конструктора суперкласса

// тело конструктора подкласса

}

Если в теле конструктора подкласса инструкцию super не указать вовсе, в качестве конструктора суперкласса вызывается конструктор по умолчанию (конструктор без аргументов). Пример описания конструкторов при наследовании приведен в листинге 3.

Листинг 3. Конструкторы и наследование

// Суперкласс:

class MySuperClass{

int a;

void showa(){

System.out.println("Объект с полем a="+a);}

// Конструкторы суперкласса:

MySuperClass(){

a=0;

showa();}

MySuperClass(int i){

a=i;

showa();}

}

// Подкласс:

class MySubClass extends MySuperClass{

double x;

void showx(){

System.out.println("Объект с полем x="+x);}

// Конструкторы подкласса:

MySubClass(){

super(); // Вызов конструктора суперкласса

x=0;

showx();}

MySubClass(int i,double z){

super(i); // Вызов конструктора суперкласса

x=z;

showx();}

}

class SuperConstrDemo{

public static void main(String[] args){

System.out.println("Первый объект:");

MySubClass obj1=new MySubClass();

System.out.println("Второй объект:");

MySubClass obj2=new MySubClass(5,3.2);}

}

В результате выполнения этой программы получаем последовательность сообщений:

Первый объект:

Объект с полем a=0

Объект с полем x=0.0

Второй объект:

Объект с полем a=5

Объект с полем x=3.2

Программа состоит из трех классов. В первом классе MySuperClass описано целочисленное поле a, метод showa() для отображения значения этого поля, а также два варианта конструкторов: без аргументов и с одним аргументом. В конструкторе без аргументов полю a присваивается нулевое значение. В конструкторе с аргументом полю присваивается значение аргумента. В обоих случаях с помощью метода showa() значение поля a выводится на экран.

На основе класса MySuperClass создается подкласс MySubClass. Непосредственно в классе описывается поле x типа double и метод showx() для отображения значения этого поля.

В подклассе определяются два конструктора: без аргументов и с двумя аргументами. В каждом из этих конструкторов с помощью инструкции super вызывается конструктор суперкласса. В конструкторе подкласса без аргументов командой super() вызывается конструктор суперкласса без аргументов. Если при создании объекта подкласса конструктору передаются два аргумента (типа int и типа double), то аргумент типа int передается аргументом конструктору суперкласса (командой super(i) в теле конструктора подкласса с двумя аргументами).

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

 

Многоуровневое наследование

Хотя множественное наследование (наследование сразу нескольких классов) в Java не допускается, с успехом может использоваться многоуровневое наследование. В этом случае подкласс становится суперклассом для другого подкласса.

Пример такой ситуации приведен в листинге 7.

Листинг 7. Многоуровневое наследование

class A{

int a;

A(int i){

a=i;

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

}

class B extends A{

int b;

B(int i,int j){

super(i);

b=j;

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

}

class C extends B{

int c;

C(int i,int j,int k){

super(i,j);

c=k;

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

}

class MultiCall{

public static void main(String args[]){

C obj=new C(1,2,3);}

}

Ситуация достаточно простая: класс A является суперклассом для подкласса B. Класс B, в свою очередь, является суперклассом для подкласса C. Таким образом, получается своеобразная иерархия классов. В классе A всего одно числовое поле a и конструктор с одним аргументом. Аргумент определяет значение поля создаваемого объекта. Кроме того, при этом выводится сообщение о значении поля объекта.

В классе B наследуется поле a из класса A и появляется еще одно поле b. Соответственно, конструктор имеет два аргумента. Первый передается конструктору суперкласса (класс A), а второй определяет значение нового поля b. Также выводится сообщение о значении этого поля, однако прежде сообщение о значении поля a выводится конструктором суперкласса.

Два поля a и b наследуются в классе C. Там же описано числовое поле c. Первые два аргумента конструктора передаются конструктору суперкласса (класса B), а третий присваивается в качестве значения полю c. В конструкторе класса C имеется также команда вывода на экран значения этого поля. Значения полей a и b выводятся при выполнении конструктора суперкласса.

В главном методе программы командой C obj=new C(1,2,3) создается объект класса C. В результате на экране появляются сообщения:

Поле a: 1

Поле b: 2

Поле c: 3

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

Листинг 8. Многоуровневое наследование, перегрузка и переопределение методов

class A{

void show(){

System.out.println("Метод класса А");}

}

class B extends A{

void show(String msg){

System.out.println(msg);}

}

class C extends B{

void show(){

System.out.println("Метод класса C");}

}

class MultiOverride{

public static void main(String args[]){

A obj1=new A();

B obj2=new B();

C obj3=new C();

obj1.show();

obj2.show();

obj2.show("Класс В");

obj3.show();

obj3.show("Класс С");}

}

Как и в предыдущем примере, создается иерархическая цепочка из трех классов: в вершине находится суперкласс A, на основе которого создается подкласс B, в свою очередь являющийся суперклассом для подкласса C. При этом классами наследуется, перегружается или переопределяется описанный в классе A метод show(). Схему перегрузки и переопределения этого метода иллюстрирует рис. 1.

В частности, метод show() класса A не имеет аргументов и выводит сообщение Метод класса А. В классе B этот метод наследуется. Кроме того, в классе B метод show() перегружен с текстовым аргументом так, что он выводит сообщение, переданное в качестве его аргумента. Забегая наперед, отметим, что текстовый аргумент — это объект класса String. Текстовая строка, при передаче аргументом, заключается в двойные кавычки.

 


Рис. 1. Схема перегрузки и переопределения метода show() при многоуровневом наследовании

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

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

Метод класса А

Метод класса А

Класс В

Метод класса C

Класс С

Из объекта класса A вызывается версия метода без аргументов. Из объекта класса B метод вызывается без аргументов (версия метода из класса A) и с текстовым аргументом (версия метода, описанная в классе B). Вызываемая из объекта класса C версия метода без аргумента описана в классе C, а версия метода с текстовым аргументом наследуется из класса B.

 

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

В 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 касается описания полей (переменных). В этом случае оно означает запрет на изменение значения поля, то есть фактически означает определение константы.

 

Наследование и переопределение методов

Одним из фундаментальных механизмов, лежащих в основе любого объектно-ориентированного языка, в том числе Java, является наследование. Наследование позволяет одним объектам получать характеристики других объектов. Представим себе ситуацию, когда на основе уже существующего, проверенного и работающего кода нужно создать новую программу. Есть два пути решения этой задачи. Во-первых, можно скопировать уже существующий код в новый проект и внести необходимые изменения. Во-вторых, в новом проекте можно сделать ссылку на уже существующий код. Второй вариант во многих отношениях предпочтительнее, поскольку позволяет сэкономить время и усилия на создание нового кода и обеспечивает более высокую степень совместимости программ. Ведь если окажется, что базовый код необходимо доработать, то это достаточно сделать единожды: поскольку код инкапсулируется через ссылку, внесенные изменения вступят в силу автоматически во всех местах, где этот код используется.

Именно по этому принципу реализован механизм наследования. С практической точки зрения наследование позволяет одним объектам получать (наследовать) свойства других объектов. Реализуется наследование путем создания классов на основе уже существующих классов. При этом члены класса, на основе которого создается новый класс, с некоторыми оговорками, автоматически включаются в новый класс. Кроме того, в создаваемый класс можно добавлять новые члены. Согласно общепринятой терминологии, класс, на основе которого создается новый класс, называется суперклассом. Новый создаваемый на основе суперкласса класс называется подклассом.

Создание подкласса

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

Для реализации наследования в описании подкласса после имени класса указывается ключевое слово extends и имя суперкласса. Во всем остальном описание подкласса не отличается от описания обычного класса (то есть класса, который создается «с нуля»). Синтаксис описания подкласса имеет вид:

class A extends B{

// код

}

В данном случае подкласс A создается на основе суперкласса B. В результате подкласс A получает (наследует) открытые и защищенные члены класса B.

Обращаем внимание читателя, что в языке Java, в отличие от языка С++, отсутствует множественное наследование, то есть подкласс в Java может создаваться на основе только одного суперкласса. При этом в Java, как и в С++, существует многоуровневое наследование: подкласс, в свою очередь, может быть суперклассом для другого класса. Благодаря многоуровневому наследованию можно создавать целые цепочки связанных механизмом наследования классов. В листинге 1 приведен пример создания подкласса.

Листинг 1. Создание подкласса

class A{ // Суперкласс

int i,j;

void showij(){

System.out.println("Поля i и j: "+i+" и "+j);}

}

class B extends A{ // Подкласс

int k;

void showk(){

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

void sum(){

// Обращение к наследуемым полям:

System.out.println("Сумма i+j+k="+(i+j+k));}

}

class AB{

public static void main(String arg[]){

// Объект суперкласса:

A SuperObj=new A();

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

B SubObj=new B();

SuperObj.i=10;

SuperObj.j=20;

SuperObj.showij();

SubObj.i=7;

SubObj.j=8;

SubObj.k=9;

SubObj.showij();

SubObj.showk();

SubObj.sum();}

}

В программе описан суперкласс A, в котором объявлены два целочисленных поля i и j, а также метод showij() для отображения значений этих полей. На основе класса A создается класс B (подкласс суперкласса A). Непосредственно в теле класса B описано целочисленное поле k, а также методы showk() и sum() для вывода значения поля k и вычисления суммы полей i, j и k. Обращаем внимание, что хотя поля i и j непосредственно в классе B не описаны, в классе B о них известно, поскольку они наследуются этим классом (то есть у класса B имеются целочисленные поля i и j) и к ним можно обращаться.

В методе main() класса AB создаются два объекта: объект SuperObj суперкласса A и объект SubObj подкласса B. Полям i и j объекта SuperObj присваиваются значения 10 и 20 соответственно, после чего с помощью метода showij() значения полей выводятся на экран. Полям i, j и k объекта SubObj присваиваются целочисленные значения 7, 8 и 9. Методом showij() отображаются значения полей i и j, а значение поля k отображается с помощью метода showk(). Наконец, сумма полей вычисляется методом sum(). Результат выполнения программы следующий:

Поля i и j: 10 и 20

Поля i и j: 7 и 8

Поле k: 9

Сумма i+j+k=24

Другими словами, ситуация такая, как если бы поля i и j, а также метод showij() были описаны в классе B. Достигается такой эффект благодаря наследованию.

 


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

Адаптации растений и животных к жизни в горах: Большое значение для жизни организмов в горах имеют степень расчленения, крутизна и экспозиционные различия склонов...

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

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

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



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

0.142 с.