JavaRush /Blog Java /Random-PL /Podpis metody

Podpis metody

Opublikowano w grupie Random-PL
Cześć! Opanowałeś już tworzenie własnych klas z polami i metodami. Dzisiaj porozmawiamy szczegółowo o metodach. Oczywiście robiliśmy to nie raz podczas naszych wykładów, ale rozmawialiśmy głównie o kwestiach ogólnych. Dzisiaj dosłownie przeanalizujemy metody „w częściach” - dowiemy się, z czego się składają, jakie istnieją opcje ich tworzenia i jak tym wszystkim można zarządzać :) Do dzieła!Podpis metody - 1

Podpis metody

Cały kod opisujący metodę nazywany jest deklaracją metody . Sygnatura metody zawiera nazwę metody i typy parametrów w określonej kolejności. Ogólny wygląd reklamy można opisać następująco:
модификатор доступа, тип возвращаемого значения, Nazwa метода(список параметров) {
    // тело метода
}
Weźmy przykład deklaracji kilku metod klasy Dog.
public class Dog {

   String name;

   public Dog(String name) {
       this.name = name;
   }

   public static void main(String[] args) {
       Dog max = new Dog(„Maks”);
       max.woof();

   }

   public void woof() {
       System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
   }

   public void run(int meters) {
       System.out.println("Собака по имени " + name + " пробежала " + meters + " метров!");
   }

   public String getName() {
       return name;
   }
}

1. Modyfikator dostępu

Modyfikator dostępu jest zawsze wyświetlany jako pierwszy. Wszystkie metody klasy Dogsą oznaczone modyfikatorem public. Oznacza to, że możemy je wywołać z dowolnej innej klasy:
public class Main {

   public static void main(String[] args) {

       Dog butch = new Dog("Бутч");
       butch.run(100);
   }

}
Metody klasowe Dog, jak widać, są w klasie łatwo dostępne Main. Jest to możliwe dzięki modyfikatorowi public. W Javie istnieją inne modyfikatory i nie wszystkie pozwalają na użycie metody w innej klasie. Porozmawiamy o nich w innych wykładach. Najważniejsze to pamiętać za co odpowiada modyfikator: dostępność/niedostępność metody w innych klasach :)

2. Słowo kluczowe statyczne

Jedna z metod Dog, a mianowicie, main()jest oznaczona słowem kluczowym static. Jeśli istnieje, należy go podać po modyfikatorze dostępu. Pamiętasz, jak w poprzednich wykładach mówiliśmy o zmiennych klas statycznych? W odniesieniu do metod słowo to ma w przybliżeniu takie samo znaczenie. Jeśli metoda jest określona jako static, oznacza to, że można jej używać bez odniesienia do konkretnego obiektu klasy. I rzeczywiście, aby uruchomić metodę statyczną main()w klasie, Dognie trzeba tworzyć instancji Dog; działa ona bez niej. Gdyby ta metoda nie była statyczna, to aby z niej skorzystać musielibyśmy najpierw stworzyć obiekt.

3. Zwróć wartość.

Jeśli nasza metoda musi coś zwrócić, wówczas wskazujemy typ zwracanej wartości. Można to zobaczyć na przykładzie gettera getName():
public String getName() {
   return name;
}
Zwraca obiekt typu String. Jeśli metoda nic nie zwraca, zamiast typu podaje się słowo kluczowe void, tak jak w metodzie woof():
public void woof() {
   System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}

Metody o tej samej nazwie

Zdarzają się sytuacje, gdy nasz program wymaga kilku opcji działania metody. Dlaczego nie stworzymy własnej sztucznej inteligencji? Amazon ma Alexę, Yandex ma Alicję, więc dlaczego jesteśmy gorsi? :) W filmie o Iron Manie Tony Stark stworzył własną, wybitną sztuczną inteligencję - JARVIS Oddajmy hołd wspaniałej postaci i nazwijmy naszą AI na jej cześć :) The pierwszą rzeczą, której musimy nauczyć Jarvisa - witać osoby wchodzące do pokoju (dziwne byłoby, gdyby tak wielki intelekt okazał się niegrzeczny).
public class Jarvis {

   public void sayHi(String name) {
       System.out.println("Dobry wieczór, " + name + ", Jak się masz?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi(„Tony'ego Starka”);
   }
}
Wyjście konsoli:

Добрый вечер, Тони Старк, Jak ваши дела?
Świetnie! Jarvis wie, jak przywitać wchodzącego. Najczęściej będzie to oczywiście jego właściciel – Tony Stark. Ale nie może przyjść sam! Nasza metoda sayHi()przyjmuje tylko jeden argument jako dane wejściowe. I odpowiednio będzie mógł powitać tylko jednego z przychodzących, a drugiego zignoruje. Niezbyt grzecznie, prawda?:/ W tym przypadku, aby rozwiązać problem, możemy po prostu napisać w klasie 2 metody o tej samej nazwie, ale o różnych parametrach:
public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Dobry wieczór, " + firstGuest + ", Jak się masz?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Dobry wieczór, " + firstGuest + ", " + secondGuest + ", Jak się masz?");
   }

}
Nazywa się to przeciążaniem metody . Przeciążenie pozwala naszemu programowi być bardziej elastycznym i uwzględniać różne opcje pracy. Sprawdźmy jak to działa:
public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Dobry wieczór, " + firstGuest + ", Jak się masz?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Dobry wieczór, " + firstGuest + ", " + secondGuest + ", Jak się masz?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi(„Tony'ego Starka”);
       jarvis.sayHi(„Tony'ego Starka”, "Kapitan Ameryka");
   }
}
Wyjście konsoli:

Добрый вечер, Тони Старк, Jak ваши дела? 
Добрый вечер, Тони Старк, Капитан Америка, Jak ваши дела?
Świetnie, obie opcje zadziałały :) Jednak nie rozwiązaliśmy problemu! A co jeśli gości jest trzech? Oczywiście możemy ponownie przeciążyć metodę, sayHi()aby zaakceptować nazwiska trzech gości. Ale może być ich 4 lub 5. I tak w nieskończoność. Czy istnieje inny sposób nauczenia Jarvisa pracy z dowolną liczbą nazw, bez miliona przeciążeń metod sayHi()? :/ Oczywiście, że tak! Czy w przeciwnym razie Java byłaby najpopularniejszym językiem programowania na świecie? ;)
public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Dobry wieczór, " + name + ", Jak się masz?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi(„Tony'ego Starka”);
       System.out.println();
       jarvis.sayHi(„Tony'ego Starka”, "Kapitan Ameryka");
   }
}
Rekord ( String...names) przekazywany jako parametr pozwala wskazać, że do metody przekazana została określona liczba ciągów znaków. Nie określamy z góry, ile ich ma być, dlatego działanie naszej metody staje się teraz znacznie bardziej elastyczne:
public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Dobry wieczór, " + name + ", Jak się masz?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi(„Tony'ego Starka”, "Kapitan Ameryka", "Czarna Wdowa", "Ponton");
   }
}
Wyjście konsoli:

Добрый вечер, Тони Старк, Jak ваши дела? 
Добрый вечер, Капитан Америка, Jak ваши дела? 
Добрый вечер, Черная Вдова, Jak ваши дела? 
Добрый вечер, Халк, Jak ваши дела?
Wewnątrz metody przeglądamy wszystkie argumenty i wyprowadzamy gotowe frazy z nazwami do konsoli. Tutaj używamy uproszczonej pętli for-each(już się z nią spotkałeś). To świetne rozwiązanie, ponieważ pisanie String...namesw rzeczywistości oznacza, że ​​kompilator umieszcza wszystkie przekazane parametry w tablicy. Dlatego namesmożesz pracować ze zmienną tak samo, jak z tablicą, łącznie z przeglądaniem jej w pętli. Co więcej, będzie działać dla dowolnej liczby przesyłanych linii! Dwa, dziesięć, a nawet tysiąc – metoda sprawdzi się niezawodnie przy dowolnej liczbie gości. O wiele wygodniejsze niż przeciążanie wszystkich możliwych opcji, prawda? :) Podajmy kolejny przykład przeciążania metod. Dodajmy metodę do Jarvisa printInfoFromDatabase(). Wypisuje informacje o osobie z bazy danych na konsolę. Jeśli baza danych wskazuje, że dana osoba jest superbohaterem lub superzłoczyńcą, informacja ta zostanie wyświetlona również na ekranie:
public class Jarvis {

   public  void printInfoFromDatabase (String bio) {

       System.out.println(bio);
   }

   public void printInfoFromDatabase(String bio, boolean isEvil, String nickname) {

       System.out.println(bio);
       if (!isEvil) {
           System.out.println("Также известен Jak супергерой " + nickname);
       } else {
           System.out.println("Также известен Jak суперзлодей " + nickname);
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.printInfoFromDatabase("Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Waszyngton");
       System.out.println();
       jarvis.printInfoFromDatabase("Макс Эйзенхарт. Рост 188см, вес 86 кг.", true, "Магнето");
   }
}
Wniosek:

Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Waszyngton
Макс Эйзенхарт. Рост 188см, вес 86 кг 
Также известен Jak суперзлодей Магнето
Tak działa nasza metoda w zależności od danych jakie do niej przekazujemy. Kolejny ważny punkt:Kolejność argumentów ma znaczenie! Załóżmy, że nasza metoda pobiera na wejściu ciąg znaków i liczbę:
public class Man {

   public static void sayYourAge(String greeting, int age) {
       System.out.println(greeting + " " + age);
   }

   public static void main(String[] args) {

       sayYourAge("Mój wiek - ", 33);
       sayYourAge(33, "Mój wiek - "); //błąd!
   }
}
Jeśli metoda sayYourAge()klasowa Manprzyjmuje na wejściu ciąg znaków i liczbę, to w takiej kolejności należy je przekazać do programu! Jeśli przekażemy je w innej kolejności, kompilator zgłosi błąd i dana osoba nie będzie w stanie określić swojego wieku. Nawiasem mówiąc, konstruktory, które omawialiśmy w ostatnim wykładzie, są także metodami! Można je również przeciążać (utworzyć kilka konstruktorów z różnymi zestawami argumentów) i dla nich kolejność przekazywania argumentów również ma fundamentalne znaczenie. Prawdziwe metody! :)

Jak wywoływać metody o podobnych parametrach

Jak wiadomo, w Javie istnieje takie słowo jak null. Podczas pracy z nim bardzo ważne jest, aby zrozumieć, że wartość null nie jest ani obiektem, ani typem danych. Wyobraź sobie, że mamy klasę Man i metodę introduce(), która deklaruje imię i wiek osoby. W tym przypadku wiek można przekazać w formie tekstowej lub można go wyrazić liczbą.
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man sasha = new Man();
       sasha.introduce(„Sasza”, "двадцать один");

       Man masha = new Man();
       masha.introduce("Мария", 32);
   }
}
Przeciążanie jest już nam znane, więc wiemy, że metoda będzie działać zgodnie z oczekiwaniami w obu przypadkach:

Меня зовут Саша, мой возраст - двадцать один 
Меня зовут Мария, мой возраст - 32 
Ale co się stanie, jeśli jako drugi parametr przekażemy wartość null, a nie ciąg znaków lub liczbę?
public static void main(String[] args) {

   Man victor = new Man();
   victor.introduce("Виктор", null);//Ambiguous method call!
}
Otrzymamy błąd kompilacji! Błąd „Niejednoznaczne wywołanie metody” jest tłumaczony jako „niejednoznaczne wywołanie metody”. Dlaczego mogło się to zdarzyć i na czym polega „niejednoznaczność”? To właściwie proste. Rzecz w tym, że mamy dwa warianty metody: z Stringi z Integerjako drugim argumentem. Ale oba String, i Integermogą mieć wartość null! W przypadku obu typów (ponieważ są to typy referencyjne) wartością domyślną jest null. Dlatego kompilator w tej sytuacji nie może ustalić, którą wersję metody powinien wywołać. Rozwiązanie tego problemu jest dość proste. Chodzi o to, że wartość null można jawnie przekonwertować na określony typ referencyjny. Dlatego wywołując metodę, możesz wskazać w nawiasie typ danych potrzebnych dla drugiego argumentu! Kompilator zrozumie Twoją „podpowiedź” i wywoła wymaganą metodę:
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Метод со строкой и числом!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", (String) null);
   }
}
Wniosek:

Метод с двумя строками! 
Меня зовут Виктор, мой возраст - null
Gdyby jednak parametr numeryczny był pierwotny int, a nie obiektem typu referencyjnego Integer, taki błąd nie wystąpiłby.
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, int age) {
       System.out.println("Метод со строкой и числом!!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", null);
   }
}
Czy zgadłeś dlaczego? Jeśli zgadłeś, dobra robota :) Ponieważ prymitywy nie mogą być równe null. Teraz kompilator ma tylko jedną opcję wywołania metody introduce()- za pomocą dwóch linii. To właśnie ta wersja metody będzie przetwarzana przy każdym wywołaniu metody.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION