1. Передавання параметрів

А тепер починається найцікавіше. Як ви вже, напевно, знаєте завдяки знайомству з методами типу System.out.println(), у методи можна передавати параметри. І це значно збільшує користь від створення й використання методів.

Як же оголосити метод з параметрами? Насправді це досить просто:

public static void ім'я(параметри)
{
   код методу
}

де ім'я — це унікальне ім'я методу, код методу — це команди, з яких він складається, а параметри — це параметри методу, перелічені через кому. Подивіться на цей шаблон в деталях:

public static void ім'я(тип1 ім'я1, тип2 ім'я2, тип3 ім'я3)
{
   код методу
}

Приклади:

Код Пояснення
public static void print(String str)
{
}
Оголошено метод print з параметром
String str
public static void print(String str, int count)
{
}
Оголошено метод print із двома параметрами
String str
int count
public static void write(int x, int y)
{
}
Оголошено метод write із двома параметрами
int x
int y

Якщо нашому метод параметри не потрібні, просто залишаємо круглі дужки порожніми.

Параметри — це спеціальні змінні методу. З їх допомогою в метод можна передавати різні значення під час його виклику.

Для прикладу спробуймо написати метод, який виводить на екран рядок тексту задану кількість разів.

Як написати код для кількаразового виведення рядка на екран, ви вже знаєте. Але який саме рядок виводити? І скільки разів? Ось для цього нам і знадобляться параметри.

Код цієї задачі матиме такий вигляд:

Код Пояснення
class Solution
{
   public static void printLines(String text, int count)
   {
     for (int i = 0; i < count; i++)
       System.out.println(text);
   }

   public static void main(String[] args)
   {
     printLines("Привіт", 10);
     printLines("Бувай", 20);
   }
}


Оголосили метод printLines з параметрами:
String text, int count
Метод виводить на екран count разів рядок text





Викликаємо метод printLines з різними параметрами

Кожного разу, коли викликається метод, його змінним-параметрам присвоюються передані значення, і лише потім починається виконання команд усередині методу.


2. Аргументи методу

Ще трохи вашої уваги хочемо звернути на виклик методу з параметрами.

Значення, що передаються в метод під час його виклику, прийнято називати аргументами методу.

Розгляньмо приклад ще раз:

Код Пояснення
class Solution
{
   public static void printLines(String text, int count)
   {
     for (int i = 0; i < count; i++)
       System.out.println(text);
   }

   public static void main(String[] args)
   {
     printLines("Привіт", 10);
     printLines("Бувай", 20);
   }
}


Оголосили метод printLines з параметрами:
String text, int count
Метод виводить на екран count разів рядок text




Викликаємо метод printLines з параметрами
text = "Привіт"; count = 10;
text = "Бувай"; count = 20;

Коли метод printLines було викликано вперше, його змінним-параметрам було присвоєно такі значення:
String text = "Привіт", int count = 10.

Коли метод printLines було викликано вдруге, його змінним-параметрам було присвоєно інші значення:
String text = "Бувай", int count = 20.

Параметри методу — це саме змінні, яким присвоюються певні значення під час виклику методу. Самі ж значення "Привіт", "Бувай", 10 і 20 називають аргументами методу.


3. Конфлікт імен змінних під час виклику методу

Як аргументи методу можна використовувати змінні. Це просто й зрозуміло, але потенційно може спричиняти деякі складнощі. Розгляньмо той самий приклад, але винесемо аргументи в окремі змінні:

Код Пояснення
class Solution
{
   public static void printLines(String text, int count)
   {
     for (int i = 0; i < count; i++)
       System.out.print(text);
   }

   public static void main(String[] args)
   {
     String str = "Привіт";
     int n = 10;
     printLines(str, n);
   }
}


Оголосили метод printLines з параметрами:
String text, int count
Метод виводить на екран count разів рядок text







Викликаємо метод printLines з параметрами:
text = str;
count = n;

Поки що нічого складного: у нас є змінна str, її значення присвоюється змінній text під час виклику методу. У нас є змінна n, її значення присвоюється змінній count під час виклику методу. Досі все зрозуміло.

А тепер перейменуймо наші змінні в методі main:

Код Пояснення
class Solution
{
   public static void printLines(String text, int count)
   {
     for (int i = 0; i < count; i++)
       System.out.print(text);
   }

   public static void main(String[] args)
   {
     String text = "Привіт";
     int count = 10;
     printLines(text, count);
   }
}


Оголосили метод printLines з параметрами:
String text, int count
Метод виводить на екран count разів рядок text







Викликаємо метод printLines з параметрами:
text = text;
count = count;

Зверніть увагу на дві речі.

Перше: у нас є змінні з однаковими іменами в різних методах. Це різні змінні (ми їх спеціально пофарбували різними кольорами). Усе працює так само, як і в попередньому прикладі, коли змінні в методі main називалися str і n.

Друге: під час виклику методу ніякого чаклунства не відбувається. Змінним-параметрам просто присвоюються значення аргументів, незалежно від того, чи це конкретні числа, рядки, змінні або вирази.

Після перейменування змінних у методі main нічого не змінилося. Це як були різні змінні в різних методах, так і залишились. Жодного магічного зв'язку між змінними text і text немає.



4. Передавання посилань в методи

Сподіваємося, ви зрозуміли все з попередньої лекції, тому що зараз ми знову розглянемо передавання аргументів у методи, тільки докладніше.

Як ви вже знаєте, деякі змінні в Java зберігають не самі значення, а адресу (посилання) блока пам'яті, в якому ці значення розміщені. Так працюють, наприклад, змінні-рядки або змінні-масиви.

Коли ви присвоюєте змінній-масиву іншу змінну-масив, що відбувається? Правильно. Дві змінні починають посилатися на один і той самий контейнер у пам'яті:

А що відбудеться, якщо одна з цих змінних буде змінною-параметром методу?

Код Пояснення
class Solution
{
   public static void sum(int[] data)
   {
     int summa = 0;
     for (int i = 0; i < data.length; i++)
       summa = summa + data[i];
     System.out.println(summa);
   }
   
   public static void main(String[] args)
   {
     int[] months = {31, 28, 31, 30, 31, 30, 31, 31, 30};
     sum(months);
   }
}


Метод sum обчислює суму чисел переданого масиву й виводить її на екран

Відбудеться точнісінько те саме: змінна-параметр data міститиме посилання на той самий контейнер, що й змінна months. Під час виклику методу просто буде здійснено присвоювання data = months.

А оскільки обидві змінні посилаються на один і той самий контейнер цілих чисел, то метод sum може не просто читати значення з масиву, а й змінювати їх!

Приміром, ми можемо написати свій власний метод, який заповнює двовимірний масив однаковими значеннями. Отакий вигляд міг би мати цей метод:

Код Пояснення
class Solution
{
   public static void fill(int[][] data, int value)
   {
     for (int i = 0; i < data.length; i++)
     {
       for (int j = 0; j < data[i].length; j++)
         data[i][j] = value;
     }
  }

   public static void main(String[] args)
   {
     int[][] months = {{31, 28}, {31, 30, 31}, {30, 31, 31}};
     fill (months, 8);
   }
}


Метод fill пробігає всіма комірками переданого двовимірного масиву та присвоює їм значення value.








Створюємо двовимірний масив.
Заповнюємо весь масив числом 8.


5. Методи з однаковими іменами

А зараз знову повернемося до імен методів.

Стандарти Java вимагають, щоб усі методи всередині одного класу мали унікальні імена. Тобто неможливо оголосити в одному класі два однакові методи.

Тільки от у процесі перевірки методів на однаковість враховуються не лише імена, але й типи параметрів! Причому імена змінних-параметрів не враховуються. Приклади:

Код Пояснення
void fill(int[] data, int value) {
}
void fill(int[][] data, int value) {
}
void fill(int[][][] data, int value)  {
}
Ці три методи вважаються різними. Їх можна оголосити в одному класі.
void print(String str) {
}
void print(String str, String str2) {
}
void print(int val) {
}
void print(double val) {
}
void print() {
}
Усі ці п'ять методів вважаються різними. Їх можна оголосити в одному класі.
void sum(int x, int y) {
}
void sum(int data, int value) {
}
Ці два методи вважаються однаковими (їх не можна оголосити в одному класі).

Чому ж одні методи вважаються однаковими, а інші — різними? І чому не враховуються імена змінних-параметрів під час визначення унікальності методу?

Навіщо взагалі потрібна унікальність? Річ у тім, що коли компілятор компілює вашу програму, він має точно знати, яку саме функцію/метод ви викликаєте в певному місці.

Наприклад, ви пишете System.out.println("Привіт"). Компілятор розумний, і він легко зробить висновок, що тут викликається метод println() з параметром типу String.

А якщо ви напишете System.out.println(1.0), компілятор побачить тут виклик методу println() з параметром типу double.

Компілятор стежить, щоб під час виклику методу типи аргументів і параметрів збігалися, а на ім'я аргументу не звертає уваги. У Java імена змінних-параметрів жодним чином не допомагають компілятору визначити метод, який викликається. Тому вони й не враховуються під час визначення унікальності методу.

Ім'я методу й типи його параметрів називають сигнатурою методу. Приклад: sum(int, int)

Кожен клас має містити не методи з унікальними іменами, а методи з унікальними сигнатурами.