Главная страница

Лабораторная работа 1 2 лабораторная работа 2 31 лабораторная работа 3 44 лабораторная работа 4 74


Скачать 1.76 Mb.
НазваниеЛабораторная работа 1 2 лабораторная работа 2 31 лабораторная работа 3 44 лабораторная работа 4 74
Дата12.03.2021
Размер1.76 Mb.
Формат файлаdoc
Имя файлаOOP_Lab_Rus.doc
ТипЛабораторная работа
#184105
страница25 из 31
1   ...   21   22   23   24   25   26   27   28   ...   31

6.2 Перегрузка методов.


Перегрузка методов поддерживает полиморфизм, потому что это один из способов, с помощью которых Java реализует парадигму «один интерфейс, множество методов». Чтобы понять, как это делается, приведем следующие рассуждения. На языках, которые не поддерживают перегрузку методов, каждому методу необходимо давать уникальное имя. Однако часто нужно реализовать, по существу, один и тот же метод для различных типов данных. Рассмотрим функцию абсолютного значения. На языках, которые не поддерживают перегрузку, существует обычно три или более версий этой функции, каждая со слегка отличающимся именем. Например, в C, функция abs() возвращает абсолютное значение целого числа, labs() возвращает абсолютное значение длинного целого числа, a fabs() — абсолютное значение числа с плавающей точкой. Так как C не поддерживает перегрузку, каждая функция должна иметь свое собственное имя, даже при том, что все три функции выполняют, по существу, одно и то же. Это делает ситуацию более сложной, чем она фактически есть на самом деле. Хотя основная концепция каждой функции одна и та же, вам все еще нужно помнить три разных имени. Подобная ситуация отсутствует в Java, потому что метод получения абсолютного значения един для всех типов данных. Действительно, библиотека стандартных классов Java включает метод абсолютного значения, с именем abs(). Этот метод перегружен в Math-классе Java, чтобы обрабатывать все числовые типы. Java определяет, какую версию abs() вызывать, основываясь на типе аргумента. Значение перегрузки заключается в том, что она позволяет осуществлять доступ к связанным методам при помощи общего имени. Таким образом, имя abs представляет общее выполняемое действие. Право же выбирать правильную специфическую версию для конкретного обстоятельства предоставлено компилятору. Вы же, как программист, должны только помнить общую выполняемую операцию. При использовании полиморфизма несколько имен были сокращены до одного. Хотя этот пример довольно прост, но если расширить концепцию, то можно увидеть, как перегрузка может помочь вам управлять большей сложностью.

6.3 Динамическая диспетчеризация методов


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

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

Вот пример, который иллюстрирует динамическую диспетчеризацию методов:
// Динамическая диспетчеризация методов.

class A {

void callme() {

System.out.println("Внутри A метод callme");

}

}

class B extends A {

// переопределить callme()

void callme() {

System.out.println("Внутри B метод callme");

}

}

class C extends A {

// переопределить callme ()

void callme() {

System.out.println("Внутри C метод callme");

}

}

class Dispatch {

public static void main(String args[]) {

A a = new A(); // объект типа A

B b = new B(); // объект типа B

C c = new C(); // объект типа C

A r; // определить ссылку типа A
r = a; // r на A-объект

r.callme(); // вызывает A-версию callme

r = b; // r указывает на B-объект

r. callme(); // вызывает B-версию callme

r = c; // r указывает на C-объект

r.callme(); // вызывает C-версию callme

}

}
Вывод этой программы:
Внутри A метод callme

Внутри B метод callme

Внутри C метод callme
Эта программа создает один суперкласс c именем A и два его подкласса B и C. Подклассы B и C переопределяют callme(), объявленный в A. Внутри метода main() объявлены объекты типа A, B и C. Объявлена также ссылка типа A с именем r. Затем программа назначает ссылку r на каждый тип объекта и использует эту ссылку, чтобы вызвать соответствующий метод callme(). Как показывает вывод, версия выполняемого callme() определяется типом объекта, на который указывает ссылка во время вызова. Если бы она была определена типом ссылочной переменной r, вы увидели бы три обращения к методу callme() из класса A.
1   ...   21   22   23   24   25   26   27   28   ...   31


написать администратору сайта