CodeGym /Blog Java /Random-PL /Deklaracja metody
Autor
Oleksandr Miadelets
Head of Developers Team at CodeGym

Deklaracja metody

Opublikowano w grupie Random-PL
Cześć! Wiesz już o tworzeniu własnych klas z polami i metodami. Teraz zajmiemy się metodami.
Deklaracja metody - 1
Oczywiście robiliśmy to już nie raz na naszych lekcjach, ale głównie omówiliśmy ogólniki. Dzisiaj przeanalizujemy metody i zbadamy, z czego są zrobione, różne sposoby ich tworzenia i sposoby zarządzania tym wszystkim. :) Chodźmy!

Deklaracja metody

Cały kod definiujący metodę jest nazywany deklaracją metody . Ogólną postać deklaracji metody można opisać następująco:

access modifier, return type, method name (parameter list) {
    // method body
}
Jako przykłady spójrz na deklaracje różnych 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("Max");
       max.woof();

   }

   public void woof() {
       System.out.println("A dog named " + name + " says \"Woof, woof!\"");
   }

   public void run(int distanceInFeet) {
       System.out.println("A dog named " + name + " ran " + distanceInFeet + " feet!");
   }

   public String getName() {
       return name;
   }
}

1. Modyfikator dostępu

Modyfikator dostępu jest zawsze wskazywany jako pierwszy. Wszystkie Dogmetody klasy są 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");
       butch.run(100);
   }

}
Jak widać, Dogmetody klasy są łatwo dostępne w Mainklasie. Jest to możliwe dzięki modyfikatorowi public . W Javie istnieją inne modyfikatory. Nie wszystkie pozwalają na użycie metod w innych klasach. Porozmawiamy o nich na innych lekcjach. Najważniejszą rzeczą do zapamiętania jest to , za co odpowiada modyfikator: czy metoda jest dostępna w innych klasach :)

2. statyczne słowo kluczowe

Jedna z Dogmetod, main(), jest oznaczona słowem kluczowym static . Jest to również część deklaracji metody i znamy już jego znaczenie. Nie wspomnieliśmy o tym w szablonie deklaracji metody podanym na początku lekcji, ponieważ jest to opcjonalne. Jeśli jest określony, musi znajdować się po modyfikatorze dostępu. Pamiętasz, jak na ostatnich lekcjach mówiliśmy o zmiennych statycznych (klasowych)? Po zastosowaniu do metod to słowo kluczowe ma mniej więcej to samo znaczenie. Jeśli metoda jest static , to może być używana bez odniesienia do konkretnego obiektu klasy. I rzeczywiście, nie potrzebujesz Dogobiektu do uruchomienia metody statycznej main()wDogklasa. Bez niego będzie działać dobrze. Gdyby ta metoda nie była statyczna, musielibyśmy najpierw utworzyć obiekt, aby ją uruchomić.

3. Zwracana wartość

Jeśli nasza metoda ma coś zwrócić, to określamy typ zwracanej wartości. Widać to na przykładzie gettera getName():

public String getName() {
   return name;
}
Zwraca Stringobiekt. Jeśli metoda nic nie zwraca, zamiast tego używane jest słowo kluczowe voidwoof() , tak jak w metodzie:

public void woof() {
   System.out.println("A dog named " + name + " says \"Woof, woof!\"");
}

Metody o tej samej nazwie

Są sytuacje, w których będziemy potrzebować kilku różnych sposobów wywołania metody. Dlaczego nie stworzyć własnej sztucznej inteligencji? Amazon ma Alexę, Apple ma Siri, więc dlaczego nie mielibyśmy go mieć? :) W filmie Iron Man Tony Stark tworzy własną niesamowitą sztuczną inteligencję, Jarvisa. Oddajmy hołd tej niesamowitej postaci i nazwijmy naszą sztuczną inteligencję na jego cześć. :) Pierwszą rzeczą, którą musimy zrobić, to nauczyć Jarvisa witać się z osobami wchodzącymi do pokoju (dziwne byłoby, gdyby tak niesamowity intelekt okazał się niegrzeczny).

public class Jarvis {

   public void sayHi(String name) {
       System.out.println("Good evening, " + name + ". How are you?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
   }
}
Wyjście konsoli: Dobry wieczór, Tony Stark. Jak się masz? Bardzo dobry! Jarvis może teraz przyjmować gości. Oczywiście częściej niż będzie to jego mistrz, Tony Stark. Ale co jeśli nie przyjdzie sam! Ale nasza sayHi()metoda akceptuje tylko jeden argument. I tak może powitać tylko jedną osobę wchodzącą do pokoju, a drugą zignoruje. Niezbyt grzecznie, zgadzasz się? :/ W takim przypadku możemy rozwiązać problem, po prostu pisząc 2 metody o tej samej nazwie, ale różnych parametrach:

public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Good evening, " + firstGuest + ". How are you?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
   }

}
Nazywa się to przeciążaniem metody . Przeciążanie metod sprawia, że ​​nasz program jest bardziej elastyczny i dostosowuje się do różnych sposobów pracy. Sprawdźmy, jak to działa:

public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Good evening, " + firstGuest + ". How are you?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
       jarvis.sayHi("Tony Stark", "Captain America");
   }
}
Wyjście konsoli: Dobry wieczór, Tony Stark. Jak się masz? Dobry wieczór, Tony Stark i Kapitanie Ameryko. Jak się masz? Świetnie, obie wersje zadziałały. :) Ale nie rozwiązaliśmy problemu! A co jeśli jest trzech gości? Moglibyśmy oczywiście sayHi()ponownie przeciążyć metodę, tak aby akceptowała trzy nazwy gości. Ale może być ich 4 lub 5. Aż do nieskończoności. Czy nie ma lepszego sposobu nauczenia Jarvisa obsługi dowolnej liczby nazw bez przeciążania metody sayHi()milion razy ()? :/ Oczywiście, że tak! Gdyby nie było, czy myślisz, że Java byłaby najpopularniejszym językiem programowania na świecie? ;)

public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Good evening, " + name + ". How are you?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
       System.out.println();
       jarvis.sayHi("Tony Stark", "Captain America");
   }
}
Gdy ( String... names ) jest używany jako parametr, oznacza to, że kolekcja Strings zostanie przekazana do metody. Nie musimy z góry określać, ile ich będzie, więc teraz nasza metoda jest znacznie bardziej elastyczna:

public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Good evening, " + name + ". How are you?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
   }
}
Wyjście konsoli: Dobry wieczór, Tony Stark. Jak się masz? Dobry wieczór, Kapitanie Ameryko. Jak się masz? Dobry wieczór Czarna Wdowo. Jak się masz? Dobry wieczór, Hulk. Jak się masz? Wewnątrz metody iterujemy po wszystkich argumentach i wyświetlamy frazy sformatowane z nazwami. Tutaj używamy uproszczonej for-eachpętli (którą widziałeś wcześniej). Tutaj jest to idealne rozwiązanie, ponieważ notacja ( String... names ) faktycznie oznacza, że ​​kompilator umieszcza wszystkie przekazane argumenty w tablicy. W rezultacie możemy pracować z nazwami zmiennychtak jakbyśmy pracowali z tablicą, włączając w to iterację po niej w pętli. Ponadto będzie działać z dowolną liczbą przekazanych ciągów! Dwóch, dziesięciu, a nawet tysiąca – metoda sprawdzi się przy dowolnej liczbie gości. O wiele wygodniejsze niż przeciążanie metody dla wszystkich możliwości, nie sądzisz? :) Oto kolejny przykład przeciążania metody. Dajmy Jarvisowi printInfoFromDatabase()metodę. Wyświetli informacje o osobie z bazy danych. Jeśli baza danych wskazuje, że dana osoba jest superbohaterem lub superzłoczyńcą, wyświetlimy tę informację:

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("Also known as the superhero " + nickname);
       } else {
           System.out.println("Also known as the supervillain " + nickname);
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.printInfoFromDatabase("Laura Palmer. Date of birth: July 22, 1972. Twin Peaks, Washington");
       System.out.println();
       jarvis.printInfoFromDatabase("Max Eisenhardt. Height: 15.6 ft. Weight: 189 lbs. ", true, "Magneto");
   }
}
Wyjście: Laura Palmer. Data urodzenia: 22 lipca 1972. Twin Peaks, Waszyngton Max Eisenhardt. Wzrost: 15,6 stopy. Waga: 189 funtów. Znany również jako supervillain Magneto . Zachowanie naszej metody zależy od danych, które do niej przekazujemy. Oto kolejna ważna kwestia: kolejność argumentów ma znaczenie! Powiedzmy, że nasza metoda pobiera ciąg znaków i liczbę:

public class Person {

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

   public static void main(String[] args) {

       sayYourAge("My age is ", 33);
       sayYourAge(33, "My age is "); // Error!
   }
}
Jeśli metoda Personklasy sayYourAge()pobiera ciąg znaków i liczbę jako dane wejściowe, to jest to kolejność, w jakiej te argumenty muszą zostać przekazane do metody! Jeśli przekażemy je w innej kolejności, to kompilator wygeneruje błąd i osoba nie będzie mogła podać swojego wieku. Nawiasem mówiąc, konstruktory, o których mówiliśmy na ostatniej lekcji, to także metody! Można je też przeciążać (np. tworzyć kilka konstruktorów z różnymi zestawami parametrów) i kolejność przekazywanych argumentów też jest dla nich fundamentalnie ważna. To są prawdziwe metody! :)

Jak wywoływać metody o podobnych parametrach

Jak wiesz, nulljest słowem kluczowym w Javie. Bardzo ważne jest, aby zrozumieć, że nullnie jest to ani obiekt, ani typ danych . Wyobraź sobie, że mamy Personklasę i introduce()metodę, która ogłasza imię i wiek osoby. Ponadto wiek można przekazać jako tekst lub liczbę.

public class Person {

   public void introduce(String name, String age) {
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public static void main(String[] args) {

       Person alex = new Person();
       alex.introduce ("Alex", "twenty-one");

       Person mary = new Person();
       mary.introduce("Mary", 32);
   }
}
Znamy już przeciążanie, więc wiemy, że obie metody będą zachowywać się tak, jak powinny: Nazywam się Alex. Mam dwadzieścia jeden lat. Mam na imię Mary. Mam 32 lata Ale co się stanie, jeśli jako drugi parametr przekażemy nullzamiast ciągu znaków lub liczby?

public static void main(String[] args) {

   Person victor = new Person();
   victor.introduce("Victor", null);// Ambiguous method call!
}
Otrzymamy błąd kompilacji! Co to powoduje i na czym dokładnie polega ta „niejednoznaczność”? W rzeczywistości wszystko jest bardzo proste. Problem polega na tym, że mamy dwie wersje metody: jedną z a Stringjako drugim argumentem i drugą z a Integerjako drugim argumentem. Ale a Stringi an Integermogą być obydwoma null! Ponieważ są to typy referencyjne, nulljest wartością domyślną dla obu z nich. Dlatego w tej sytuacji kompilator nie może ustalić, którą wersję metody powinien wywołać. Rozwiązanie tego problemu jest dość proste. Nullmożna jawnie przekonwertować na określony typ referencyjny. Tak więc, kiedy wywołujesz metodę, możesz wskazać w nawiasach typ danych, który chcesz dla drugiego argumentu! Kompilator zrozumie twoją „podpowiedź” i wywoła poprawną metodę:

public class Person {

   public void introduce(String name, String age) {
       System.out.println("Method with two strings!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Method with a string and a number!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public static void main(String[] args) {

       Person victor = new Person();
       victor.introduce("Victor", (String) null);
   }
}
Wyjście: Metoda z dwoma łańcuchami! Mam na imię Wiktor. Mój wiek jest pusty Zauważ, że gdyby parametr number był typem primitive int, a nie instancją typu referencyjnego Integer, nie byłoby takiego błędu.

public class Person {

   public void introduce(String name, String age) {
       System.out.println("Method with two strings!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public void introduce(String name, int age) {
       System.out.println("Method with a string and a number!!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public static void main(String[] args) {

       Person victor = new Person();
       victor.introduce("Victor", null);
   }
}
Czy możesz zgadnąć dlaczego? Jeśli zgadłeś dlaczego, brawo! :) Ponieważ prymitywy nie mogą być null. Teraz kompilator ma tylko jeden wybór, czyli wywołać introduce()metodę z dwoma napisami. Jest to wersja metody, która będzie uruchamiana przy każdym wywołaniu metody.

Więcej czytania:

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION