Hei! Du har allerede visst om å lage dine egne klasser med felt og metoder. Nå skal vi dvele ved metoder.
Metodeerklæring - 1
Selvfølgelig har vi allerede gjort dette mer enn én gang i leksjonene våre, men vi har hovedsakelig dekket generelt. I dag skal vi dissekere metoder, og studere hva de er laget av, de ulike måtene å lage dem på, og hvordan vi kan håndtere det hele. :) La oss gå!

Metodeerklæring

All koden som definerer en metode kalles en metodeerklæring . Den generelle formen for en metodeerklæring kan beskrives som følger:

access modifier, return type, method name (parameter list) {
    // method body
}
Som eksempler, ta en titt på deklarasjonene til de ulike metodene i klassen 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. Tilgangsmodifikator

Tilgangsmodifikatoren indikeres alltid først. Alle Dogklassens metoder er merket med den offentlige modifikatoren. Dette betyr at vi kan ringe dem fra en hvilken som helst annen klasse:

public class Main {

   public static void main(String[] args) {

       Dog butch = new Dog("Butch");
       butch.run(100);
   }

}
Som du kan se, Doger klassens metoder lett tilgjengelige i Mainklassen. Dette er mulig på grunn av den offentlige modifikatoren. I Java er det andre modifikatorer. De tillater ikke alle metoder som kan brukes i andre klasser. Vi skal snakke om dem i andre leksjoner. Det viktigste å huske er hva modifikatoren er ansvarlig for: om en metode er tilgjengelig i andre klasser :)

2. statisk nøkkelord

En av Dogmetodene, main(), er merket med nøkkelordet static . Det er også en del av metodedeklarasjonen, og vi vet allerede dens betydning. Vi nevnte det ikke i metodedeklarasjonsmalen gitt i begynnelsen av leksjonen, fordi det er valgfritt. Hvis det er spesifisert, må det komme etter tilgangsmodifikatoren. Husker du at vi i de siste timene snakket om statiske (klasse) variabler? Når det brukes på metoder, har dette søkeordet omtrent samme betydning. Hvis en metode er statisk , kan den brukes uten referanse til et spesifikt objekt i klassen. Og faktisk, du trenger ikke et Dogobjekt for å kjøre den statiske main()metoden iDogklasse. Den går helt fint uten en. Hvis denne metoden ikke var statisk, ville vi først måtte lage et objekt for å kunne kjøre det.

3. Returverdi

Hvis metoden vår skulle returnere noe, spesifiserer vi typen returverdi. Dette er tydelig fra eksemplet med getName()getter:

public String getName() {
   return name;
}
Den returnerer et Stringobjekt. Hvis en metode ikke returnerer noe, brukes nøkkelordet voidwoof() i stedet, som i metoden:

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

Metoder med samme navn

Det er situasjoner hvor vi vil ha flere forskjellige måter å kalle en metode. Hvorfor ikke lage vår egen kunstige intelligens? Amazon har Alexa, Apple har Siri, så hvorfor skulle vi ikke ha en? :) I filmen Iron Man skaper Tony Stark sin egen utrolige kunstige intelligens, Jarvis. La oss hylle den fantastiske karakteren og navngi vår AI til hans ære. :) Det første vi må gjøre er å lære Jarvis å si hei til folk som kommer inn i rommet (det ville vært rart om et så fantastisk intellekt viste seg å være uhøflig).

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");
   }
}
Konsoll-utgang: God kveld, Tony Stark. Hvordan har du det? Veldig bra! Jarvis kan nå ta imot gjester. Selvfølgelig, oftere enn det vil være hans mester, Tony Stark. Men hva om han ikke kommer alene! Men sayHi()metoden vår godtar bare ett argument. Og så kan den bare hilse på én person som kommer inn i rommet, og vil ignorere den andre. Ikke veldig høflig, enig? :/ I dette tilfellet kan vi løse problemet ved å skrive 2 metoder med samme navn, men forskjellige parametere:

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?");
   }

}
Dette kalles metodeoverbelastning . Metodeoverbelastning lar programmet vårt være mer fleksibelt og imøtekomme ulike måter å jobbe på. La oss se på hvordan det fungerer:

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");
   }
}
Konsoll-utgang: God kveld, Tony Stark. Hvordan har du det? God kveld, Tony Stark og Captain America. Hvordan har du det? Utmerket, begge versjonene fungerte. :) Men vi løste ikke problemet! Hva om det er tre gjester? Vi kunne selvfølgelig overbelaste sayHi()metoden igjen, slik at den godtar tre gjestenavn. Men det kan være 4 eller 5. Helt til det uendelige. Finnes det ikke en bedre måte å lære Jarvis å håndtere et hvilket som helst antall navn, uten å overbelaste metoden sayHi()en million ganger()? :/ Selvfølgelig er det det! Hvis det ikke var det, tror du Java ville vært det mest populære programmeringsspråket i verden? ;)

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");
   }
}
Når ( String... names ) brukes som en parameter, indikerer det at en samling av strenger vil bli sendt til metoden. Vi trenger ikke spesifisere på forhånd hvor mange det blir, så nå er metoden vår mye mer fleksibel:

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");
   }
}
Konsoll-utgang: God kveld, Tony Stark. Hvordan har du det? God kveld, Captain America. Hvordan har du det? God kveld, Black Widow. Hvordan har du det? God kveld, Hulk. Hvordan har du det? Inne i metoden itererer vi over alle argumentene og viser fraser formatert med navn. Her bruker vi en forenklet for-eachloop (som du har sett før). Det er perfekt her, fordi ( String... names )-notasjonen betyr faktisk at kompilatoren legger alle beståtte argumenter i en matrise. Som et resultat kan vi jobbe med variabelnavnsom vi ville jobbet med en matrise, inkludert ved å iterere gjennom den i en sløyfe. I tillegg vil det fungere med et hvilket som helst antall beståtte strenger! To, ti, til og med tusen – metoden vil fungere riktig med et hvilket som helst antall gjester. Mye mer praktisk enn å overbelaste metoden for alle mulighetene, tror du ikke? :) Her er et annet eksempel på metodeoverbelastning. La oss gi Jarvis en printInfoFromDatabase()metode. Den vil vise informasjon om en person fra en database. Hvis databasen indikerer at en person er en superhelt eller superskurk, viser vi denne informasjonen:

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");
   }
}
Utgang: Laura Palmer. Fødselsdato: 22. juli 1972. Twin Peaks, Washington Max Eisenhardt. Høyde: 15,6 fot. Vekt: 189 lbs. Også kjent som superskurken Magneto Så, metodens oppførsel avhenger av dataene vi sender til den. Her er et annet viktig poeng: rekkefølgen på argumentene betyr noe! La oss si at metoden vår tar en streng og et tall:

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!
   }
}
Hvis Personklassens sayYourAge()metode tar en streng og et tall som input, så er dette rekkefølgen som disse argumentene må sendes til metoden! Hvis vi sender dem i en annen rekkefølge, vil kompilatoren generere en feil og personen vil ikke kunne si alderen sin. Forresten, konstruktører, som vi dekket i forrige leksjon, er også metoder! Du kan også overbelaste dem (dvs. lage flere konstruktører med forskjellige sett med parametere) og rekkefølgen på beståtte argumenter er grunnleggende viktig for dem også. De er ekte metoder! :)

Hvordan påkalle metoder med lignende parametere

Som du vet, nuller et nøkkelord i Java. Det er veldig viktig å forstå at det nullverken er et objekt eller en datatype . Tenk deg at vi har en Personklasse og en introduce()metode, som annonserer personens navn og alder. Videre kan alderen passeres som tekst eller tall.

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);
   }
}
Vi er allerede kjent med overbelastning, så vi vet at begge metodene vil oppføre seg som de skal: Jeg heter Alex. Min alder er tjueen. Jeg heter Mary. Min alder er 32. Men hva vil skje hvis vi passerer nullsom den andre parameteren i stedet for en streng eller et tall?

public static void main(String[] args) {

   Person victor = new Person();
   victor.introduce("Victor", null);// Ambiguous method call!
}
Vi får en kompileringsfeil! Hva forårsaker dette og hva er egentlig "tvetydigheten"? Faktisk er det hele veldig enkelt. Problemet er at vi har to versjoner av metoden: en med a Stringsom det andre argumentet, og en med en Integersom det andre argumentet. Men a Stringog en Integerkan begge være null! Fordi de er referansetyper, nuller standardverdien for dem begge. Det er derfor i denne situasjonen kompilatoren ikke kan finne ut hvilken versjon av metoden den skal kalle. Løsningen på dette problemet er ganske enkel. Nullkan eksplisitt konverteres til en bestemt referansetype. Når du kaller en metode, kan du altså angi i parentes hvilken datatype du ønsker for det andre argumentet! Kompilatoren vil forstå "hintet" og kalle den riktige metoden:

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);
   }
}
Utgang: Metode med to strenger! Jeg heter Victor. Min alder er null Merk at hvis tallparameteren var en primitiv int, i stedet for en forekomst av referansetypen heltall, ville det ikke ha vært en slik feil.

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);
   }
}
Kan du gjette hvorfor? Hvis du gjettet hvorfor, bra gjort! :) Fordi primitiver kan ikke være null. Nå har kompilatoren kun ett valg, dvs. å kalle introduce()metoden med to strenger. Dette er versjonen av metoden som vil kjøre hver gang metoden kalles.