Вход/Регистрация
Java: руководство для начинающих
вернуться

Шилдт Герберт

Шрифт:

}

class OverloadDemo { public static void main(String args[]) { Overload ob = new Overload; int resl; double resD; // вызвать все варианты метода ovlDemo ob.ovlDemo; System.out.println; ob.ovlDemo(2) ; System.out.println; resl = ob.ovlDemo(4, 6) ; System.out.println("Result of ob.ovlDemo(4, 6): " + resl); System.out.println; resD = ob.ovlDemo(1.1, 2.32); System.out.println("Result of ob.ovlDemo(1.1, 2.32): " + resD); }

} Как видите, метод ovlDemo перегружается четырежды. В первом его варианте параметры не предусмотрены, во втором — определен один целочисленный параметр, в третьем — два целочисленных параметра, в четвертом — два параметра типа double. Обратите внимание на то, что первые два варианта метода ovlDemo имеют тип void, а два другие возвращают значение. Как пояснялось ранее, тип возвращаемого значения не учитывается при перегрузке методов. Следовательно, попытка определить два варианта метода ovlDemo так, как показано ниже, приводит к ошибке.

// Возможен лишь один вариант метода ovlDemo (int). // Возвращаемое значение нельзя использовать // для различения перегружаемых методов. void ovlDemo(int а) { System.out.println("One parameter: " + a); } / Ошибка! Два варианта метода ovlDemo(int) не могут существовать, даже если типы возвращаемых ими значений отличаются. / int ovlDemo(int а) { System.out.println("One parameter: " + a); return a * a; } Как поясняется в комментариях к приведенному выше фрагменту кода, отличия возвращаемых типов недостаточно для перегрузки методов. Как следует из главы 2, в Java производится автоматическое приведение типов. Это приведение распространяется и на типы параметров перегружаемых методов. В качестве примера рассмотрим следующий фрагмент кода:

/ Автоматическое преобразование типов может оказывать влияние на выбор перегружаемого метода. / class 0verload2 { void f(int x) { System.out.println("Inside f(int): " + x) ; } void f(double x) { System.out.println("Inside f(double): " + x) ; }

}

class TypeConv { public static void main(String args[]) { overload2 ob = new 0verload2; int i = 10; double d = 10.1; byte b = 99; short s = 10; float f = 11.5F; ob.f(i); // Вызов метода оb.f(int) ob.f(d); // Вызов метода ob.f(double) ob.f(b); // Вызов метода oh.f(int) с преобразованием типов ob.f(s); // Вызов метода ob.f(int) с преобразованием типов ob.f(f); // Вызов метода ob.f(double) с преобразованием типов }

} Выполнение этого фрагмента кода дает следующий результат:

Inside f (int) : 10 Inside f(double): 10.1 Inside f (int): 99 Inside f(int): 10 Inside f(double): 11.5 В данном примере определены только два варианта метода f : один принимает параметр типа int, а второй — параметр типа double. Но передать методу f можно также значение типа byte, short или float. Значения типа byte и short исполняющая система Java автоматически преобразует в тип int. В результате будет вызван вариант метода f (int). А если параметр имеет значение типа float, то оно преобразуется в тип double и далее вызывается вариант метода f (double). Важно понимать, что автоматическое преобразование типов выполняется лишь в отсутствие прямого соответствия типов параметра и аргумента. В качестве примера ниже представлена другая версия предыдущей программы, в которой добавлен вариант метода f с параметром типа byte.

// Добавление варианта метода f(byte). class 0verload2 { void f(byte x) { System.out.println("Inside f(byte): " + x) ; } void f(int x) { System.out.println("Inside f(int) : " + x); } void f(double x) { System.out.printlnpinside f(double): " + x); }

}

class TypeConv { public static void main(String args[]) { 0verload2 ob = new 0verload2; int i = 10; double d = 10.1; byte b = 99; short s = 10; float f = 11.5F; ob.f(i); // Вызов метода ob.f(int) ob.f(d); // Вызов метода ob.f(double) ob.f(b); // Вызов метода ob.f(byte) без преобразования типов ob.f(s) ; // Вызов метода ob.f (int) с преобразованием (типов ob.f(f) ; // Вызов метода ob.f(double) с преобразованием типов }

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

Inside f(int): 10 Inside f(double): 10.1 Inside f(byte): 99 Inside f(int): 10 Inside f(double): 11.5 В данной версии программы используется вариант метода f с параметром типа byte. Так, если при вызове метода f ему передается значение типа byte, вызывается вариант метода f (byte) и автоматическое приведение к типу int не производится. Перегрузка методов представляет собой механизм воплощения полиморфизма, т.е. способ реализации в Java принципа “один интерфейс — множество методов”. Для того чтобы стёбю понятнее, как и для чего это делается, необходимо принять во внимание следующее соображение: в языках программирования, не поддерживающих перегрузку методов, каждый метод должен иметь уникальное имя. Но в ряде случаев требуется выполнять одну и ту же последовательность операций над разными типами данных. В качестве примера рассмотрим функцию, определяющую абсолютное значение. В языках, не поддерживающих перегрузку методов, приходится создавать три или более варианта данной функции с именами, отличающимися хотя бы одним символом. Например, в языке С функция abs возвращает абсолютное значение числа типа int, функция labs — абсолютное значение числа типа long, а функция f abs применяется к значению с плавающей точкой. А поскольку в С не поддерживается перегрузка, то каждая из функций должна иметь свое собственное имя, несмотря на то, что все они выполняют одинаковые действия. Это приводит к неоправданному усложнению процесса написания программ. Разработчику приходится не только представлять себе действия, выполняемые функциями, но и помнить все три их имени. Такая ситуация не возникает в Java, потому что все методы, вычисляющие абсолютное значение, имеют одно и то же имя. В стандартной библиотеке Java для вычисления абсолютного значения предусмотрен метод abs . Его перегрузка осуществляется в классе Math для обработки значений всех числовых типов. Решение о том, какой именно вариант метода abs должен быть вызван, исполняющая система Java принимает, исходя из типа аргумента. Главная ценность перегрузки заключается в том, что она обеспечивает доступ к связанным вместе методам по общему имени. Следовательно, имя abs обозначает общее выполняемое действие, а компилятор сам выбирает конкретный вариант метода по обстоятельствам. Благодаря полиморфизму несколько имен сводятся к одному. Несмотря на всю простоту рассматриваемого здесь примера, продемонстрированный в нем принцип полиморфизма можно расширить, чтобы выяснить, каким образом перегрузка помогает справляться с более сложными ситуациями в программировании. Когда метод перегружается, каждый его вариант может выполнять какое угодно действие. Для установления взаимосвязи между перегружаемыми методами не существует какого-то твердого правила, но с точки зрения правильного стиля программирования перегрузка методов подразумевает подобную взаимосвязь. Следовательно, использовать одно и то же имя для несвязанных друг с другом методов не следует, хотя это и возможно. Например, имя sqr можно было бы выбрать для методов, возвращающих квадрат и квадратный корень числа с плавающей точкой. Но ведь это принципиально разные операции. Такое применение перегрузки методов противоречит ее первоначальному назначению. На практике перегружать следует только тесно связанные операции. ## Перегрузка конструкторов Как и методы, конструкторы также могут перегружаться. Это дает возможность конструировать объекты самыми разными способами. В качестве примера рассмотрим следующую программу:

// Демонстрация перегрузки конструкторов, class MyClass { int х; // Конструкторы перегружаются разными способами. MyClass { System.out.println("Inside MyClass."); x = 0 ; } MyClass(int i) { System.out.println("Inside MyClass(int) . ") ; x = i; } MyClass(double d) { System.out.println("Inside MyClass(double)."); x = (int) d; } MyClass(int i, int j) { System.out.println("Inside MyClass(int, int)."); x = i * j; }

}

class OverloadConsDemo { public static void main(String args[]) { MyClass tl = new MyClass; MyClass t2 = new MyClass(88); MyClass t3 = new MyClass(17.23); MyClass t4 = new MyClass(2, 4); System.out.println("tl.x: " + tl.x); System.out.println("t2.x: " + t2.x); System.out.println("t3.x: " + t3.x); System.out.println("t4.x: " + t4.x); }

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

Inside MyClass. Inside MyClass(int). Inside MyClass(double). Inside MyClass(int, int). tl.x: 0 t2.x: 88 t3.x: 17 t4.x: 8 В данном примере конструктор MyClass перегружается четырежды. Во всех вариантах этого конструктора объект типа MyClass строится по-разному. Конкретный вариант конструктора выбирается из тех параметров, которые указываются при выполнении оператора new. Перегружая конструктор класса, вы предоставляете пользователю созданного вами класса свободу в выборе способа конструирования объекта. Перегрузка конструкторов чаще всего производится для того, чтобы дать возможность инициализировать один объект на основании другого объекта. Рассмотрим в качестве примера следующую программу, в которой класс Summation используется для вычисления суммы двух целочисленных значений.

  • Читать дальше
  • 1
  • ...
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: