Освоюємо Java/Методи

Матеріал з Вікіпідручника

Методи в Java — це закінчена послідовність дій (інструкцій), спрямованих на вирішення окремого завдання. По суті це добре знайомі функції (вони ж процедури, підпрограми) більш ранніх, не ООП мов. Лишень ці функції є членами класів і задля розрізнення із звичайними функціями, згідно термінології об'єктно-орієнтованого програмування функції-члени називаються методами.

Визначення методу[ред.]

В загальному метод описується(визначається) наступним чином:

тип-повернення ідентифікатор-методу (параметри)
{
   тіло методу
   
   return повертаєме-значення // якщо void, то інструкція return не обов'язкова
}

Тобто необхідно вказати тип значення, що метод повертатиме, наприклад double, float і т.д. або ж void - якщо нічого не повертає. ідентифікатор-методу - це його назва, за якого до нього звертатимуться. Методи рекомендується іменувати з маленької букви, наприклад, sum, addSum і т.д. В дужках вказується параметри методу через кому. При вказанні параметру необхідно вказати його тип та назву.

Більш повне визначення метода в класі наступне:

class MyClass
{
 ...
    public ReturnType methodName( ParamOneType param1, ParamTwoType param2 ) throws ExceptionName
    {
      ReturnType retType;
      ...
      return retType;
    }
 ...
}


Якщо метод не повертає нічого, то в якості типу-повернення використовується ключове слово "void"

private void methodName( String param1, String param2 )
{
 ...
  return;
}


Ключове слово "return" в кінці метода можна пропустити. Крім того "return" може застосовуватись будь-де в методі, якщо необхідно закінчити виконання метода, наприклад, після виконання певної умови.

В наступному прикладі використовується метод sum() для знаходження суми трьох чисел та його виклик.

public class ProgramSum{
    public static void main(String[] args) {	
        int a=2, b=3, k=4;
        int sum=sum(a, b, k);
        System.out.println("Сума трьох чисел дорівнює "+sum);
    }
    public static int sum (int a, int b, int c){
        return a+b+c;
    }    
}


Як бачимо спочатку оголошуються і ініціалізуються змінні a, b, k. В подальшому дані змінні передаються у метод sum(), де вони сумуються і повертається їхня сума. Результат присвоюється змінній sum. Яка і виводиться на екран. В результаті на екрані з'явиться наступний напис:

Сума трьох чисел дорівнює 9 

Зверніть увагу, що третій параметр у тілі метода носить інше ім’я – «c», а не «k». Це демонструє те, що назви параметрів у методі не пов’язані з назвами, які використані при виклику метода. При його виклику відбувається ініціалізація нових змінних зі списку параметрів методу відповідними значеннями змінних, що використані при його виклику (аргументів).

З виходом Java 5 з'явилася можливість викликати методи із змінною кількістю аргументів одного типу. Для цього метод оголошують наступним чином:

public double sum(double...nums)

Наступний приклад демонструє як можна підрахувати суму масиву використовуючи метод оголошений таким чином:

public class TestArgs {
	static double   k[]={5.1, 5.2, 5.3, 5.4, 5.5};
	
	public static double sum(double...nums){
		double sum=0;
		System.out.println("Кількість аргументів="+nums.length);
        for ( double n : nums )              
        	sum+=n;
        
        return sum;
	}
	
	static public void main(String[] args) {
		System.out.println("Сума="+sum(k ));
		System.out.println("Сума="+sum(33.4, 2.0));
		
	}
}

Результат:

Кількість аргументів=5
Сума=26.5
Кількість аргументів=2
Сума=35.4

В разі потреби таким чином можна створити і метод для прийому різної кількості масивів, наприклад, sum(double[]...nums). Якщо необхідно, щоб метод приймав і інші аргументи, то відповідні параметри йдуть спочатку, а згодом конструкуція для змінної кількості аргументів, наприклад sum(int k, double...nums).

Перевантаження методів[ред.]

В мові Java в межах одного класу можна визначити два або й більше методів під одним іменем, що мають параметри, які відрізняються або кількістю, або типом. Такі методи називаються перевантаженими, а сам процес як перевантаження (англ. overloading) методів. Це один із способів реалізації поліморфізму.

Наступний приклад демонструє перевантаження методу sum:

public class ProgramSum{
    public static void main(String[] args) {
        int a=2, b=3, k=4;
        double a1=2.10, b1=4.20, k1=5.30;
        int sum=sum(a, b, k);
        double sum2=sum(a1, b1, k1);
        System.out.println("Сума трьох цілих чисел дорівнює: "+sum);
        System.out.println("Сума трьох дробових чисел дорівнює: "+sum2);
    }
    public static int sum (int a, int b, int c){
        return a+b+c;
    }
    public static double sum (double a, double b, double c){
        return a+b+c;
    }    
}

В результаті на екрані отримаємо:

Сума трьох цілих чисел дорівнює: 9
Сума трьох дробових чисел дорівнює: 11.600000000000001

Як бачимо тіло методів практично не відрізняються. Відрізняються лише типом параметрів, що приймаються і типом параметрів, що повертаються, хоча останнє може бути однаковим, або й взагалі метод може нічого не повертати. Цікаво, що якщо б не було першого методу з цілочисловими вхідними параметрами, то можливий виклик другого методу без приведення змінних до типу.

public class ProgramSum{
    public static void main(String[] args) {
        // TODO code application logic here
        int a=2, b=3, k=4;
        double a1=2.10, b1=4.20, k1=5.30;
        double sum=sum(a, b, k);
        double sum2=sum(a1, b1, k1);
        System.out.println("Сума трьох цілих чисел дорівнює: "+sum);
        System.out.println("Сума трьох дробових чисел дорівнює: "+sum2);

    }
    public static double sum (double a, double b, double c){
        return a+b+c;
    }    
}

Результат:

Сума трьох цілих чисел дорівнює: 9.0
Сума трьох дробових чисел дорівнює: 11.600000000000001 

Зверніть увагу, що результат у першій стрічці дробовий. Одержаний результат отримали через те, що Java здійснила автоматичне перетворення типів int у double. Проте зворотнє перетворення не здійснюється автоматично, якщо було б навпаки і існував лише перший метод, то при спробі виклику з double параметрами ми б отримали помилку компіляції. В таких випадках потрібно здійснювати явне приведення типів.

В наступному прикладі відбувається виклик трьох перевантажених методів. Додано метод sum() з одним цілочисловим і одним дробовим параметрами.

public class ProgramSum{
    public static void main(String[] args) {
        int a=2, b=3, k=4;
        double a1=2.10, b1=4.20, k1=5.30;
        System.out.println("Сума трьох цілих чисел дорівнює: "+sum(a, b, k));
        System.out.println("Сума трьох дробових чисел дорівнює: "+sum(a1, b1, k1));
        System.out.println("Сума одного цілого числа та одного дробового дорівнює: "+sum(a, k1));
    }
    public static int sum (int a, int b, int c){
        System.out.print("1-й метод.");
        return a+b+c;
    }
    public static double sum (double a, double b, double c){
        System.out.print("2-й метод.");
        return a+b+c;
    }
    public static double sum (int a, double b){
        System.out.print("3-й метод.");
        return a+b;
    }
}

Результат виконання.

1-й метод.Сума трьох цілих чисел дорівнює: 9
2-й метод.Сума трьох дробових чисел дорівнює: 11.600000000000001
3-й метод.Сума одного цілого числа та одного дробового дорівнює: 7.3

Можна перевантажити також методи із змінною кількістю аргументів:

static public double sum(double...nums){...}
static public double sum(int...nums){...}

Проте потрібно зважати, що sum(double...nums) та sum(double k, double...nums) буде сприйнято компілятором як методи з однаковою сигнатурою і видасть помилку, що в коді є неоднозначність. Це пояснюється тим, що такі оголошення компілятор при розборі перетворює у методи, що приймають масив і в даному випадку компілятор створить аналоги методів з одними і тими ж вхідними параметрами. Тож два однакові методи не можуть існувати в коді.

Заміщення методів[ред.]

Крім перевантаження існує також термін заміщення методів (англ. overriding). Заміщення відбувається, коли клас нащадок (підклас) визначає певний метод, який вже є у батьківському класі (надкласі), таким чином новий метод замінює метод надкласу.

У нас часто overriding перекладають як перевизначення, але в англійській мові для цього слова існує відповідник redefining, який інколи англомовні програмісти теж вживають як синонім overriding. Проте в термінології ООП прийнято вживати все ж термін overriding (заміщення), а термін перевизначення (redefining) практично не вживається, крім того між даними термінами є певна різниця. Про заміщення (overriding) говорять коли мають на увазі нестатичні методи класів, коли ж в новому класі описується нова версія статичного класу, то можна сказати, що статичний метод перевизначається (redefine), але не заміщується (override). Це пов'язано із правилами поліморфізму, які на статичні методи не поширюються, а отже повноцінна заміна (заміщення) не відбувається. В ООП перевизначення нового статичного методу у підкласі називають приховуванням (hiding) методу.[1][2] Тобто перевизначення — це можна сказати більше розмовне поняття, яке має ширше значенням ніж заміщення. Можна також трактувати це таким чином, що коли говорять про процес написання коду програмістом то можна говорити, що він перевизначає старий метод, тобто визначає, пише нову версію методу, коли ж говорити про сам код програми, її виконання, класи, об'єкти та їхню роботу із виклику нестатичних методів підкласів та надкласів, то правильніше говорити, що відбувається заміщення методу.

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

Тож маємо два класи Parent та Child.

Клас Parent:

public class Parent {
	
	public static void helloStatic(){
		System.out.println("Hello from Parent.helloStatic()");
		
	}
	public void helloNonStatic(){
		System.out.println("Hello from Parent.helloNonStatic()");
	}
	
	public void hello(){
		System.out.println("Hello from Parent.hello()");
	}
}

Як бачимо клас доволі простий і містить три методи. Один статичний і два звичайні нестатичний метод, які просто виводять рядок привітання, що містить назву класу і назву методу. Статичні методи та змінні належать класу і їх можна викликати до створення будь-яких об'єктів через назву класу. Наприклад Parent.helloStatic() При створенні об'єктів вони по суті будуть спільними для всіх об'єктів.

Тепер зробимо нащадка даного класу. Для того, щоб вказати, що клас є нащадком необхідно при оголошенні застосовують ключове слово extends за яким іде вказання назви батьківського класу.

public class Child extends Parent {
	
	public static void helloStatic(){
		System.out.println("Hello from Child.helloStatic()");
	}
	
	@Override
	public void helloNonStatic(){
		System.out.println("Hello from Child.helloNonStatic()");
	}

	public static void main(String[] args) {
		
		
		Child child=new Child(); //створюємо об'єкт Child
		child.hello();//викликаємо успадкований метод
		child.helloNonStatic();//викликаємо заміщений метод		
		child.helloStatic();//статичні методи рекомендують викликати через клас,
				    //а не через об'єкт, 
				    //тобто краще писати Child.helloStatic()
				
		
                //далі використовується поліморфізм - використовуємо об'єктну змінну батьківського класу
		//і присвоюємо їй посилання дочірнього класу
		Parent parent=new Child();
		parent.helloNonStatic(); //заміщення спрацьовує
		
		parent.helloStatic(); //заміщення не спрацьовує, 
					//викликається метод батьківського класу
	}

}

Результат виконання:

Hello from Parent.hello()
Hello from Child.helloNonStatic()
Hello from Child.helloStatic()
Hello from Child.helloNonStatic()
Hello from Parent.helloStatic()

У методі main створюється об'єкт класу Child і викликаються послідовно методи даного об'єкту. Як бачимо об'єкт дочірнього класу зміг викликати метод hello() батьківського класу оскільки успадкував його від нього (див. 1-й рядок результату). При виклику child.helloNonStatic() викликається версія методу дочірнього класу. Метод заміщено новим.

Щоб продемонструвати справжню суть заміщення і чому цей термін не ідентичний перевизначенню, у коді змінній із типом батьківського класу присвоємо посилання на об'єкт дочірнього класу:

Parent parent=new Child();

В результаті виклику parent.helloNonStatic(); відбудеться насправді виклик методу не батьківського об'єкту, а виклик методу дочірнього об'єкту. Тобто спрацювало заміщення. Це явище називається поліморфізмом. Поліморфізм ви доволі часто зустрічатимете при програмуванні на Java. Він дозволяє нам створювати нові модифіковані класи нащадки і підставляти їх у програми без необхідності переписування усіх звернень до класів предків. Детальніше у розділі присвяченому поліморфізму.

Інакший результат ми бачимо при виклику parent.helloStatic(). Викликається метод батьківського класу попри те, що змінна parent посилається на об'єкт класу Child. Тобто заміщення не спрацювало. Щоб не було таких незрозумілостей з кодом, рекомендується статичні методи викликати через назву їхнього класу. Тобто писати Parent.helloStatic(), якщо хочемо викликати статичний метод батьківського класу або ж писати Child.helloStatic(), щоб викликати статичний метод дочірнього класу.

Модифікатор final[ред.]

Метод може бути оголошений як final. Тоді не можливо буде здійснити його заміщення в класах нащадках. Вам буде видана помилка вже на процесі компіляції.

Методи із змінною кількістю аргументів[ред.]

В Java існує можливість оголосити метод із змінною кількістю аргументів.

  public static int defineArgCount(Integer... args) {
    if (args.length != 0) {
      for (int element : args) {
        System.out.printf("arg:%d ", element);
      }
    } else {
      System.out.print("No arg ");
    }   return args.length;
  }

Додаткові матеріали[ред.]

Посилання на джерела[ред.]


Рядки · Об'єкти і класи