Аргументи змінної довжини в методах. Перевантаження методів з аргументами змінної довжини. Властивість 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[][] resA; // результуючий масив
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} }

// вивід масиву resA      
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
----------------


Зв’язані теми