Методы и конструкторы
В предыдущей главе уже упоминалось такое понятие, как конструктор. Конструкторы существенно упрощают процесс создания объектов и повышают эффективность программного кода. В этой главе описываются способы создания конструкторов и способы работы с ними, а также перегрузка методов. Что касается перегрузки операторов, то она является важным механизмом реализации полиморфизма и, кроме того, имеет прямое отношение к конструкторам, поскольку конструкторы также можно перегружать, причем обычно так и поступают. Поэтому сначала мы рассмотрим тему перегрузки методов.
Перегрузка методов
Необходимость в перегрузке методов поясним на простом примере. Допустим, имеется класс с двумя числовыми полями и методом, с помощью которого задаются значения этих полей. Метод имеет два аргумента — по одному для каждого поля. Мы хотим, чтобы в случае если полям присваиваются одинаковые значения, можно было вызывать метод с одним аргументом. Если бы не было возможности перегрузить метод, пришлось бы описывать новый метод. Это неудобно, поскольку для одного и того же, по сути, действия пришлось бы использовать два разных метода. Намного разумнее и удобнее было бы вызывать один и тот же метод, но с разным количеством аргументов в зависимости от ситуации. Благодаря перегрузке методов такая возможность существует.
При перегрузке методов создается несколько методов с одинаковыми именами, но разными сигнатурами. Напомним, что сигнатура метода состоит из типа результата, возвращаемого методом, имени метода и списка аргументов. Поскольку имя общее, разные варианты метода могут отличаться типом возвращаемого результата и (или) списком аргументов. Технически речь идет о разных методах, но поскольку все они имеют одинаковые названия, обычно говорят об одном методе.
Что касается функциональности различных вариантов перегруженного метода, то формальных ограничений нет, однако общепринятым является принцип, согласно которому перегруженные версии метода должны реализовывать один общий алгоритм (поэтому обычно варианты перегруженного метода отличаются списком аргументов). В этом смысле неприемлема ситуация, когда одна версия метода, например, выводит сообщение со значением аргумента, а другая выполняет поиск наибольшего значения среди переданных методу аргументов. Хотя с технической точки зрения это возможно.
В листинге 5.1 представлен пример программы с перегруженным методом.
Листинг 5.1. Перегрузка метода
// Класс с перегруженным методом:
class OverloadDemo{
// Вариант метода без аргументов:
void test(){
System.out.pгintln("Аргументы отсутствуют!"); }
// Вариант метода с одним целым аргументом:
void test(int a){
System.out.pгintln("аргумент типа int: "+a);
}
// Вариант метода с аргументом типа double и результатом типа double: double test(double a){
System.out.println("аргумент типа double: "+a);
return a;
}}
// Класс с методом main():
class Overload{
public static void main(String args[]){
OverloadDemo obj=new OverloadDemo();
double result;
// Вызов перегруженного метода:
obj.test();
obj.test(10);
result=obj.test(12.5);
System.out.println("Результат: "+result);
}}
В программе описывается класс OverloadDemo, который содержит четыре варианта метода с названием test(). Первый вариант метода не имеет аргументов, и в результате его вызова выводится сообщение Аргументы отсутствуют! Данный вариант метода результат не возвращает. Второй вариант метода имеет аргумент типа int и также не возвращает результат. После вызова этого варианта метода появляется сообщение аргумент типа int: со значением переданного методу аргумента. Наконец, еще один вариант метода имеет аргумент типа double и в качестве результата возвращает значение типа double. После вызова метода выводится сообщение аргумент типа double: со значением аргумента, и это значение возвращается в качестве результата.
Класс Overload содержит метод main(), в котором вызываются разные варианты перегруженного метода test(). В результате выполнения программы получаем:
Аргументы отсутствуют1
Аргумент типа int: 10
Аргумент типа double: 12.5
Результат: 12.5
Обращаю внимание на то, что вызов нужного варианта метода осуществляется на основе способа этого вызова, то есть в зависимости от указанного количества аргумента и их типа. Причем при выборе «правильного» варианта перегруженного метода может возникнуть неоднозначная ситуация, особенно с учетом автоматического приведения типов. Пример такой ситуации приведен в листинге 5.2.
Листинг 5.2. Перегрузка метода и приведение типов
class OverloadDemo2{
// Метод без аргументов:
void test(){
System.out.pгintln("Аргументы отсутствуют!");}
// Метод с двумя аргументами:
void test(int a,int b){
System.out.println("аргументы типа int: "+a+" и "+b);}
// Метод с одним аргументом типа
double: void test(double a){
System.out.println("аргумент типа double: "+a);
} }
class Overload2{
public static void main(String args[]){
OverloadDemo2 obj=new OverloadDemo2();
int i=88;
obj.test();
obj.test(10,20);
obj.test(i); // приведение типа
obj.test(12.5);
}}
В классе OverloadDemo2 объявлены три варианта метода test(): без аргументов, с двумя аргументами типа int и с одним аргументом типа double. Во всех трех случаях метод не возвращает результат. В методе main() класса Overload2 метод вызывается: без аргументов, с двумя аргументами типа int, с одним аргументом типа int и с одним аргументом типа double. Несложно заметить, что вариант метода с одним аргументом типа int в классе OverloadDemo2 не предусмотрен. Тем не менее программа работает корректно:
Аргументы отсутствуют!
Аргументы типа int: 10 и 20