Аргументы переменной длины в методах. Перегрузка методов с аргументами переменной длины. Свойство length. Примеры

Аргументы переменной длины в методах. Перегрузка методов с аргументами переменной длины. Свойство length. Примеры


Содержание



1. Что такое аргументы метода? Что такое параметры метода? Какое отличие между аргументами и параметрами?

Если рассматривать объявление метода, то в нем после имени метода указывается список параметров, например

return_type SomeMethod(type1 param1, type 2 param2, ..., typeN paramN)
{
  // тело метода, использует параметры param1, param2, ..., paramN
  // ...
}

где

  • return_type – тип, возвращаемый методом;
  • SomeMethod – имя метода;
  • param1, param2, paramN – имена параметров метода, которые имеют соответственно типы type1, type2, typeN. Эти имена параметров метод использует для выполнения своей работы (функции).

Если этот метод SomeMethod() вызвать из другого кода, то в него передаются аргументы, например

...
// вызов метода, в метод передаются аргументы
SomeMethod(arg1, arg2, ..., argN);
...

где arg1, arg2, argN – аргументы, которые передаются в метод. При вызове эти аргументы неявно передаются (копируются) в параметры. Аргумент arg1 передается (копируется) в параметр param1, аргумент arg2 передается в param2, аргумент argN передается в paramN.

Итак, параметры – это переменные (константы), которые описываются в круглых скобках при объявлении метода. Аргументы – это переменные, константы, значения которые передаются в метод при его вызове из другого кода.

2. Что такое аргументы переменной длины в методах? Общая форма объявления метода с аргументами переменной длины

Аргументы переменной длины – это переменное количество аргументов, которые может получать метод при вызове из другого кода (другого метода). Другими словами, метод может вызываться с разным количеством аргументов. Такой метод называется методом с аргументами переменной длины.

Методы, которые поддерживают переменное количество аргументов должны соответствующим образом объявляться. Общая форма метода, получающего переменное количество аргументов следующая:

return_type MethodName(type ... var)
{
  // ...
  //
}

где

  • return_type – тип, возвращаемый методом;
  • MethodName – имя метода;
  • type – тип параметров переменной длины, которые получает метод. Список параметров передается в виде массива с именем var;
  • var – имя массива со списком параметров типа type.

3. В каких случаях целесообразно применять аргументы переменной длины?

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

  • упрощается программный код, так как не нужно объявлять много реализаций перегруженных методов, которые получают разное количество аргументов;
  • в метод может быть передано любое количество любых аргументов заданного типа;
  • в метод может быть передано произвольное количество аргументов любого типа. В этом случае метод должен принимать аргументы переменной длины типа Object. Такая передача не требует каких-то дополнительных преобразований в программе;
  • не нужно предварительно формировать массив значений для передачи его в метод. Значения аргументов передаются в метод через запятую.

4. Примеры методов, которые получают переменное количество аргументов

Пример 1. Объявляется метод SumParams(), который вычисляет сумму аргументов переменной длины.

// метод, который получает аргументы переменной длины
// T - массив аргументов типа int
static int SumParams(int ... T) {
  int sum = 0;
  for (int i=0; i<T.length; i++)
    sum += T[i];
  return sum;
}

Использование метода в другом программном коде

int sum;
sum = SumParams(1, 3, -2, 4, 8); // sum = 14
sum = SumParams(); // sum = 0
sum = SumParams(1, 2, 3); // sum = 6

Пример 2. Метод Max(), находящий максимум между списком аргументов.

// метод, который находит максимум между списком параметров
static double Max(double ... D)
{
  double max;
  if (D.length == 0) return 0;
    max = D[0];
  for (int i=0; i<D.length; i++)
    if (max < D[i]) max = D[i];
      return max;
}

Использование метода в другом методе

double max;
max = Max(3, 5, 2.8, 12.75); // max = 12.75
max = Max(4.33); // max = 4.33
max = Max(); // max = 0.0
max = Max(-1.5, -3.8, -112.23); // max = -1.5

Пример 3. Метод, который возвращает массив отсортированных параметров типа float. Параметры сортируются в порядке убывания.

static float[] ToSortArrayFloat(float ... F) {
  float t; // вспомогательная переменная
  if (F.length<2) return F;

  // сортировка вставкой
  for (int i=0; i<F.length-1; i++)
    for (int j=i; j>=0; j--)
      if (F[j]<F[j+1])
      {
        t = F[j];
        F[j] = F[j+1];
        F[j+1] = t;
      }
  return F;
}

Использование метода

float[] FR; // результирующий массив
FR = ToSortArrayFloat(-0.5f, 0.2f, 0.3f, -0.4f); // FR = [0.3, 0.2, -0.4, -0.5]
FR = ToSortArrayFloat(1, -2, 3); // FR = [ 3.0, 1.0, -2.0 ]
FR = ToSortArrayFloat(); // FR = [ ]

5. Как в методе определить количество аргументов переменной длины, переданных в него?

При передаче в метод аргументов переменной длины их количество определяется с помощью свойства length.

Например. Пусть задается метод Average()

// метод, вычисляющий среднее арифметическое списка параметров
static double Average(double ... list) {
  double avg=0;
  int n;

  // свойство length - общее количество параметров, переданных в метод
  n = list.length;

  // вычисление суммы элементов
  for (int i=0; i<n; i++)
    avg+=list[i];
  return avg/n;
}

В методе, в строке

n = list.length;

вычисляется общее количество аргументов переменной длины, которые были переданы в метод.

Использование метода в другом программном коде может быть, например, следующим:

double Avg;
Avg = Average(3, 5, 7, 10); // Avg = 6.25

6. Можно ли в объявлении метода объединять обычные аргументы (параметры) с аргументами переменной длины?

Да, можно. Но, при условии, что выполняются следующие правила:

  • объявление аргументов (параметров) переменной длины может следовать после объявления обычных аргументов;
  • аргументы переменной длины должны указываться в методе только один раз;
  • не допускается смешанная очередность следования обычных аргументов с аргументами переменной длины.

7. Пример объявления и использования метода, в котором используются обычные аргументы с аргументами переменной длины

Объявление метода, который получает последовательность аргументов переменной длины и возвращает двумерный массив, сформированный из этих аргументов. Размерность результирующего массива m×n задается обычными аргументами.

Реализация метода ConvertToArray2() следующая

// метод, который превращает одномерный массив параметров
// в двумерный массив заданного размера m*n
static int[][] ConvertToArray2(int m, int n, int ... params) {
  int[][] A = new int[m][n]; // результирующий массив
  int row, col;

  // обнулить массив A
  for (int i=0; i<m; i++)
    for (int j=0; j<n; j++)
      A[i][j]=0;

  int len = params.length;
  if (len>m*n) len=m*n;

  // сформировать массив A
  for (int i=0; i<len; i++)
  {
    row = i/n;
    col = i-row*n;
    A[row][col]=params[i];
  }

  // возврат массива из метода
  return A;
}

Использование массива в другом программном коде

// тестирование метода ConvertToArray2()
int[][] res; // результирующий массив
int m=2, n=3; // размерность массива

// последовательность конвертируется в двумерный массив размером 2*3
// лишние элементы урезаются
resA = ConvertToArray2(m,n,11,12,13,21,22,23,24,25,26);
// resA = { { 11, 12, 13}, { 21, 22, 23} }

// вывод массива res
for (int i=0; i<m; i++)
{
  for (int j=0; j<n; j++)
    System.out.print(" " + resA[i][j]);
  System.out.println();
}

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

11   12 13
21   22 23

8. Пример объявления и использования метода с переменным количеством аргументов, которые являются экземплярами класса

Задан класс Book, реализующий книгу

// класс, описывающий книгу
class Book {
  String title; // заголовок книги
  String author; // название автора
  int year; // год выпуска
  float price; // стоимость книги
}

Ниже приведен метод GetMaxCostBook(), получающий переменное количество аргументов типа Book. Метод возвращает ссылку на книгу, которая имеет наибольшую стоимость.

// метод, который получает массив книг в качестве параметров
// метод возвращающий книгу, которая имеет наибольшую стоимость
static Book GetMaxCostBook(Book ... B) {
  Book bk=null;

  // проверка
  if (B.length==0)
    return bk;

  // цикл вычисления книги с наибольшей стоимостью
  bk = B[0];
  for (int i=1; i<B.length; i++)
    if (bk.price<B[i].price)
      bk = B[i];

  return bk;
}

Демонстрация использования метода GetMaxCostBook() может быть такой:

// тестирование метода GetMaxCostBook()
Book B1 = new Book();
Book B2 = new Book();
Book B3 = new Book();
Book B4 = new Book();

// формирование значений книг
B1.title = "Title1";
B1.author = "Author1";
B1.price = 12.50f;
B1.year = 2007;

B2.title = "Title2";
B2.author = "Author2";
B2.price = 7.77f;
B2.year = 2023;

B3.title = "Title3";
B3.author = "Author3";
B3.price = 19.95f;
B3.year = 2019;

B4.title = "Title4";
B4.author = "Author4";
B4.price = 11.15f;
B4.year = 2009;

// вызов метода
Book resBook;
resBook = GetMaxCostBook(B1,B2,B3,B4);

if (resBook!=null)
{
  // вывод результата
  String title = resBook.title;
  String author = resBook.author;
  float price = resBook.price;
  int year = resBook.year;
  System.out.println("title = " + title);
  System.out.println("author = " + author);
  System.out.println("price = " + price);
  System.out.println("year = " + year);
}

В результате выполнения вышеприведенного кода будет выведен следующий результат

title = Title3
author = Author3
price = 19.95
year = 2019

9. Каким образом осуществляется перегрузка методов с аргументами переменной длины? Пример

Метод, который получает аргументы переменной длины, может иметь несколько перегруженных реализаций. Такие реализации отличаются между собой типом получаемых значений.

Пример. Объявляется класс CalcSum, содержащий три перегруженных реализации метода Sum(), который находит сумму параметров для типов int, double, float.

// класс, который содержит перегруженный метод Sum()
class CalcSum {
  // перегруженный метод Sum для целых типов
  int Sum(int ... params)
  {
    int sum = 0;
    for (int i=0; i<params.length; i++)
      sum+=params[i];
    return sum;
  }

  // Sum() для типа double
  double Sum(double ... params)
  {
    double sum = 0;
    for (int i=0; i<params.length; i++)
      sum+=params[i];
    return sum;
  }

  // Sum() для типа float
  float Sum(float ... params)
  {
    float sum = 0.0f;
    for (int i=0; i<params.length; i++)
      sum+=params[i];
    return sum;
  }
}

public class VarArguments {
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    CalcSum cs = new CalcSum();
    int sumInt;
    double sumDouble;
    float sumFloat;

    // вызов перегруженного метода с типом int
    sumInt = cs.Sum(2,3,5);

    // вызов перегруженного метода с типом double
    sumDouble = cs.Sum(2.05, 1.88, -3.95, 4.4);

    // вызов перегруженного метода с типом float
    sumFloat = cs.Sum(0.8f, -0.3f, 2.5f, 2.34f);

    System.out.println("sumInt = " + sumInt);
    System.out.println("sumDouble = " + sumDouble);
    System.out.println("sumFloat = " + sumFloat);
  }
}

В результате выполнения функции main() на экран будет выведен следующий результат

sumInt = 10
sumDouble = 4.38
sumFloat = 5.34

10. В чем состоит суть ошибки «неоднозначности» при использовании аргументов переменной длины?

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

Например. Пусть заданы перегруженные методы с именем Method()

static void Method(int ... params) {
  // ...
}

static void Method(boolean ... params) {
  // ...
}

то при вызове

Method(); // ошибка неоднозначности

компилятор не будет знать, какой перегруженный вариант метода Method() нужно вызвать.

Это касается комбинации существующих простых типов с типом boolean. Если объявить два перегруженных метода с типами int и double, то этой ошибки не произойдет.

11. Как сделать, чтобы метод принимал любое количество аргументов любого типа? Пример

В этом случае объявляется метод с аргументами переменной длины типа Object. Как известно, в Java все классы являются производными от общего корневого класса Object. Иногда такие методы являются еффективными, в особенности, если заведомо неизвестно тип (класс) который получает метод.

Например. Объявляется класс Error и метод ShowInfo(), принимающий аргументы переменной длины типа Object. Программный код модуля, который демонстрирует использование метода, который принимает любое количество любых аргументов

// класс, описывающий некоторую возможную ошибку в некоторой программе
class Error {
  String errorString; // название ошибки
  int code; // код ошибки

  Error(String _errorString, int _code) {
    errorString = _errorString;
    code = _code;
  }
}

public class VarArguments {
  // метод, который принимает аргументы переменной длины типа Object
  static void ShowInfo(Object ... objects) {
    String s;

    // вывод информации об аргументах, переданных в метод
    for (Object o : objects)
      System.out.println(o.toString()+" ");
    System.out.println("----------------");
  }

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    // Демонстрация использования метода ShowInfo()
    // 1. Передача аргументов типа int
    ShowInfo(3,5,7,2);

    // 2. Передача аргументов типа Error
    Error e1 = new Error("Divide by 0", 1);
    Error e2 = new Error("Abnormal program termination", 2);
    ShowInfo(e1,e2, new Object[] { new Error("Error message", 3) });

    // 3. Передача аргументов типа float
    ShowInfo(2.8, 3.55, -10.12, 18.13, 0.01);
  }
}

В результате выполнения функции main() будет выведен следующий результат

3
5
7
2
----------------
Error@1db9742
Error@106d69c
[Ljava.lang.Object;@52e922
----------------
2.8
3.55
-10.12
18.13
0.01


Связанные темы