CodeGym /Java-blogg /Tilfeldig /Metoder i Java
John Squirrels
Nivå
San Francisco

Metoder i Java

Publisert i gruppen
Hallo igjen! I siste leksjon ble vi kjent med klasser og konstruktører, og lærte å lage våre egne. I dag skal vi bli bedre kjent med Java Methods, en viktig del av timene. En Methods in Java er et sett med kommandoer som lar deg utføre en spesifikk operasjon i et program. En metode er med andre ord en funksjon; noe som klassen din er i stand til. I andre programmeringsspråk kalles metoder ofte for "funksjoner", men i Java er ordet "metode" mer vanlig. :) Hvis du husker, i den siste leksjonen laget vi enkle metoder for en kattetime , slik at kattene våre kunne si mjau og hoppe:

public class Cat {

    String name;
    int age;

    public void sayMeow() {
        System.out.println("Meow!");
    }

    public void jump() {
        System.out.println("Pounce!");
    }

    public static void main(String[] args) {
        Cat smudge = new Cat();
        smudge.age = 3;
        smudge.name = "Smudge";

        smudge.sayMeow();
        smudge.jump();
    }
}
sayMeow() og jump() er metoder i klassen vår. Og å kjøre disse metodene resulterer i følgende konsollutdata:
Meow!
Pounce!
Metodene våre er ganske enkle: de sender ganske enkelt ut tekst til konsollen. Men i Java har metoder en viktig oppgave: de utfører handlinger på et objekts data. De endrer objektets data, transformerer det, viser det og gjør andre ting med det. Våre nåværende metoder gjør ikke noe med Cat- objektets data. La oss se på et mer illustrerende eksempel:

public class Truck {

    int length;
    int width;
    int height;
    int weight;

    public int getVolume() {
        int volume = length * width * height;
        return volume;
    }
}
For eksempel, her har vi en klasse som representerer en lastebil . Semi-trucken har en lengde, bredde, høyde og vekt (som vi trenger senere). I getVolume()- metoden utfører vi beregninger, og konverterer objektets data til et tall som representerer volumet (vi multipliserer lengden, bredden og høyden). Dette tallet vil være resultatet av metoden. Merk at metodens erklæring er skrevet som public int getVolume . Det betyr at denne metoden må returnere en int . Vi regnet ut metodens returverdi, og nå må vi returnere den til programmet som kalte metoden vår. For å returnere en metodes resultat i Java bruker vi nøkkelordet return. returvolum;

Java-metodeparametere

Vi kan sende verdier kalt "argumenter" til en metode når vi kaller den. En metodes erklæring inkluderer en liste over variabler som forteller oss typen og rekkefølgen av variabler som metoden kan akseptere. Denne listen kalles "metodeparametere". Vår Truck- klasses getVolume()- metode definerer for øyeblikket ingen parametere, så la oss prøve å utvide vårt lastebileksempel. Opprett en ny klasse kalt BridgeOfficer . Dette er en politimann på vakt ved en bro, som sjekker alle passerende lastebiler for å se om lasten deres overstiger tillatt vekt.

public class BridgeOfficer {

    int maxWeight;

    public BridgeOfficer(int normalWeight) {
        this.maxWeight = normalWeight;
    }

    public boolean checkTruck(Truck truck) {
        if (truck.weight > maxWeight) {
            return false;
        } else {
            return true;
        }
    }
}
CheckTruck - metoden aksepterer ett argument, et Truck- objekt, og bestemmer om betjenten vil tillate lastebilen på broen eller ikke. Inne i metoden er logikken enkel nok: Hvis lastebilens vekt overskrider det maksimalt tillatte, returnerer metoden false . Den må finne en annen vei :( Hvis vekten er mindre enn eller lik maksimum, kan den passere, og metoden returnerer true. Hvis du ikke helt forstår setningene "retur" eller "metoden returnerer en verdi" ennå, la oss ta en pause fra programmering og vurdere dem ved å bruke et enkelt eksempel fra det virkelige liv. :) La oss si at du blir syk og blir hjemme fra jobb i noen dager. Du går til regnskapsavdelingen med legeerklæringen din, fordi sykmelding skal betales. Hvis vi sammenligner denne situasjonen med metoder, har regnskapsføreren en lønnssykefravær()metode. Du sender en legeerklæring som et argument til denne metoden (uten den fungerer ikke metoden og du får ikke betalt!). Deretter gjøres de nødvendige beregningene inne i metoden ved å bruke notatet ditt (regnskapsføreren bruker det til å beregne hvor mye selskapet skal betale deg), og resultatet av arbeidet ditt (en sum penger) blir returnert til deg. Programmet vårt fungerer på samme måte. Den kaller en metode, sender data til den og mottar til slutt et resultat. Her er BridgeOfficer- programmets hoved() -metode:

public static void main(String[] args) {
    Truck first = new Truck();
    first.weight = 10000;
    Truck second = new Truck();
    second.weight = 20000;

    BridgeOfficer officer = new BridgeOfficer(15000);
    System.out.println("Truck 1! Can I go, officer?");
    boolean canFirstTruckGo = officer.checkTruck(first);
    System.out.println(canFirstTruckGo);

    System.out.println();

    System.out.println("Truck 2! And can I?");
    boolean canSecondTruckGo = officer.checkTruck(second);
    System.out.println(canSecondTruckGo);
}
Vi lager to lastebiler med last på 10 000 og 20 000. Og brua der offiseren jobber har en maksvekt på 15.000. Programmet kaller officer.checkTruck(first) -metoden. Metoden beregner alt og returnerer deretter true , som programmet deretter lagrer til i den boolske variabelen canFirstTruckGo . Nå kan du gjøre hva du vil med den (akkurat som du kan med pengene regnskapsføreren ga deg). På slutten av dagen, koden

boolean canFirstTruckGo = officer.checkTruck(first);
koker ned til

boolean canFirstTruckGo =  true;
Her er et veldig viktig poeng: return- setningen returnerer ikke bare metodens returverdi, den stopper også metoden fra å kjøre! Enhver kode som kommer etter retursetningen vil ikke bli utført!

public boolean checkTruck(Truck truck) {

    if (truck.weight > maxWeight) {
        return false;
        System.out.println("Turn around, you're overweight!");
    } else {
        return true;
        System.out.println("Everything looks good, go ahead!");
    }
}
Offiserens kommentarer vil ikke bli vist, fordi metoden allerede har returnert et resultat og avsluttet! Programmet går tilbake til stedet der metoden ble kalt. Du trenger ikke se etter dette: Java-kompilatoren er smart nok til å generere en feil når du prøver å skrive kode etter en retursetning .

Avengers: Parameter War

Det er situasjoner hvor vi vil ha flere måter å kalle en metode på. 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:
Good evening, Tony Stark. How are you?
Veldig bra! Jarvis kan nå ta imot gjester. Selvfølgelig vil det oftere enn ikke være mesteren hans, Tony Stark. Men hva om han ikke kommer alene! Vår sayHi() -metode 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, er du ikke enig? :/

Java-metodeoverbelastning

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:
Good evening, Tony Stark. How are you?
Good evening, Tony Stark and Captain America. How are you?
Utmerket, begge versjonene fungerte. :) Men vi løste ikke problemet! Hva om det er tre gjester? Vi kan 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 sayHi()- metoden 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 void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ". How are you?");
    }
}
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:
Good evening, Tony Stark. How are you?
Good evening, Captain America. How are you?
Good evening, Black Widow. How are you?
Good evening, Hulk. How are you?
Noe kode her vil være ukjent for deg, men ikke bekymre deg for det. Det er enkelt i kjernen: Metoden tar hvert navn etter tur og hilser hver gjest velkommen! 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 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 Person -klassens sayYourAge- metode tar en streng og et tall som input, må programmet sende dem i den spesifikke rekkefølgen! Hvis vi sender dem i en annen rekkefølge, vil kompilatoren generere en feil og personen vil ikke kunne si sin alder. 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! :)

Nok en gang angående parametere

Jepp, beklager, vi er ikke ferdige med dem ennå. :) Emnet som vi skal studere nå er veldig viktig. Det er 90 % sjanse for at du blir spurt om dette ved hvert fremtidig intervju! La oss snakke om å overføre argumenter til metoder. Tenk på et enkelt eksempel:

public class TimeMachine {

    public void goToFuture(int currentYear) {
        currentYear = currentYear+10;
    }

    public void goToPast(int currentYear) {
        currentYear = currentYear-10;
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        int currentYear = 2018;

        System.out.println("What year is it?");
        System.out.println(currentYear);

        timeMachine.goToPast(currentYear);
        System.out.println("How about now?");
        System.out.println(currentYear);
    }
}
Tidsmaskinen har to metoder. De tar begge tallet som representerer inneværende år som en input, og enten øker eller reduserer verdien (avhengig av om vi ønsker å gå til fortiden eller fremtiden). Men som du kan se fra konsollutgangen, fungerer ikke metoden! Konsoll utgang:
What year is it?
2018
How about now?
2018
Vi sendte variablen currentYear til goToPast() -metoden, men verdien endret seg ikke. Vi var i 2018, og her har vi blitt. Men hvorfor? :/ Fordi primitiver i Java overføres til metoder etter verdi. Hva betyr det? Når vi kaller goToPast() -metoden og sender int -variabelen currentYear (=2018) til den, får ikke metoden selve currentYear -variabelen, men snarere en kopi av den. Selvfølgelig er verdien av denne kopien også 2018, men eventuelle endringer i kopien påvirker ikke vår opprinnelige gjeldendeÅr- variabel på noen måte! La oss gjøre koden vår mer eksplisitt og se hva som skjer med currentYear:

public class TimeMachine {

    public void goToFuture(int currentYear) {
        currentYear = currentYear+10;
    }

    public void goToPast(int currentYear) {
        System.out.println("The goToPast method has started running!");
        System.out.println("currentYear inside the goToPast method (at the beginning) = " + currentYear);
        currentYear = currentYear-10;
        System.out.println("currentYear inside the goToPast method (at the end) = " + currentYear);
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        int currentYear = 2018;

        System.out.println("What was the year when the program started?");
        System.out.println(currentYear);

        timeMachine.goToPast(currentYear);
        System.out.println("And what year is it now?");
        System.out.println(currentYear);
    }
}
Konsoll utgang:
What was the year when the program started?
2018
The goToPast method has started running!
currentYear inside the goToPast method (at the beginning) = 2018
currentYear inside the goToPast method (at the end) = 2008
And what year is it now?
2018
Dette viser tydelig at variabelen som sendes til goToPast() -metoden bare er en kopi av currentYear . Og endring av kopien påvirker ikke den "originale" verdien. "Bestå ved referanse" betyr det stikk motsatte. La oss øve på katter! Jeg mener, la oss se hvordan det å gå forbi referanse ser ut ved å bruke et katteksempel. :)

public class Cat {

    int age;

    public Cat(int age) {
        this.age = age;
    }
}
Nå sender vi Smudge , verdens første tidsreisende katt, inn i fortiden og fremtiden ved hjelp av tidsmaskinen vår ! La oss modifisere TimeMachine- klassen slik at den fungerer med Cat- objekter;

public class TimeMachine {

    public void goToFuture(Cat cat) {
        cat.age += 10;
    }

    public void goToPast(Cat cat) {
        cat.age -= 10;
    }    
}
Nå endrer ikke metodene bare det beståtte tallet. Snarere endrer de det spesifikke kattens aldersfelt . Du vil huske at dette ikke fungerte for oss med primitiver, fordi det opprinnelige nummeret ikke endret seg. La oss se hva som vil skje!

public static void main(String[] args) {

    TimeMachine timeMachine = new TimeMachine();
    Cat smudge = new Cat(5);

    System.out.println("How old was Smudge when the program started?");
    System.out.println(smudge.age);

    timeMachine.goToFuture(smudge);
    System.out.println("How about now?");
    System.out.println(smudge.age);

    System.out.println("Holy smokes! Smudge has aged 10 years! Back up quickly!");
    timeMachine.goToPast(smudge);
    System.out.println("Did it work? Have we returned the cat to its original age?");
    System.out.println(smudge.age);
}
Konsoll utgang:
How old was Smudge when the program started running?
5
How about now?
15
Holy smokes! Smudge has aged 10 years! Back up quickly!
Did it work? Have we returned the cat to its original age?
5
Wow! Nå gjorde metoden noe annerledes: katten vår eldes drastisk, men så ble den ung igjen! :) La oss prøve å finne ut hvorfor. I motsetning til eksemplet med primitiver, når objekter sendes til en metode, sendes de ved referanse. En referanse til det originale smudge- objektet ble sendt til changeAge() -metoden. Så når vi endrer smudge.age inne i metoden, refererer vi til det samme minneområdet der objektet vårt er lagret. Det er en referanse til den samme Smudge som vi opprettet i utgangspunktet. Dette kalles "passering av referanse"! Imidlertid er ikke alt med referanser så enkelt. :) La oss prøve å endre eksempelet vårt:

public class TimeMachine {

    public void goToFuture(Cat cat) {
        cat = new Cat(cat.age);
        cat.age += 10;
    }

    public void goToPast(Cat cat) {
        cat = new Cat(cat.age);
        cat.age -= 10;
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        Cat smudge = new Cat(5);

        System.out.println("How old was Smudge when the program started?");
        System.out.println(smudge.age);

        timeMachine.goToFuture(smudge);
        System.out.println ("Smudge went to the future! Has his age changed?");
        System.out.println(smudge.age);

        System.out.println ("And if you try going back?");
        timeMachine.goToPast(smudge);
        System.out.println(smudge.age);
    }
}
Konsoll utgang:
How old was Smudge when the program started running?
5
Smudge went to the future! Has his age changed?
5
And if you try going back?
5
Det fungerer ikke igjen! О_О La oss finne ut hva som skjedde. :) Det har alt å gjøre med goToPast / goToFuture -metodene og hvordan referanser fungerer. Nå, din oppmerksomhet, vær så snill! Dette er det viktigste å forstå om hvordan referanser og metoder fungerer. Faktum er at når vi kaller goToFuture(Cat cat) -metoden, er det en kopi av referansen til katteobjektet som blir bestått, ikke selve referansen. Når vi sender et objekt til en metode, er det altså to referanser til objektet. Dette er veldig viktig for å forstå hva som skjer. Det er nettopp derfor kattens alder ikke endret seg i vårt siste eksempel. I det forrige eksemplet, når vi endret alder, tok vi ganske enkelt referansen som ble sendt til goToFuture()metoden, og brukte den til å finne objektet i minnet og endre dets alder ( kat.alder += 10 ). Men nå, inne i goToFuture()- metoden, lager vi et nytt objekt ( cat = new Cat(cat.age) ), og dette objektet er tildelt samme referansekopi som ble sendt til metoden. Som et resultat:
  • Den første referansen ( Cat smudge = new Cat (5) ) peker på den originale katten (med 5 år)
  • Etter det, da vi passerte cat-variabelen goToPast()- metoden og tildelte den et nytt objekt, ble referansen kopiert.
Og dette førte oss til det endelige resultatet: to referanser som peker på to forskjellige objekter. Men vi endret bare alderen på en av dem (den som ble opprettet inne i metoden).

cat.age += 10;
Og selvfølgelig, i main() -metoden kan vi se på konsollen at kattens alder, smudge.age , ikke har endret seg. Smudge er tross alt en referansevariabel som fortsatt peker på det gamle, originale objektet med 5 år, og vi gjorde ikke noe med det objektet. Alle våre aldersendringer ble utført på det nye objektet. Så det viser seg at objekter sendes til metoder ved referanse. Kopier av objekter opprettes aldri automatisk. Hvis du sender en kattegjenstand til en metode og endrer dens alder, vil du endre alderen. Men referansevariabler kopieres når du tildeler verdier og/eller kaller metoder! La oss gjenta her det vi sa om overføring av primitiver: "Når vi kaller changeInt()- metoden og sender intvariabel x (=15) , metoden får ikke selve x -variabelen, men snarere en kopi av den. Derfor påvirker ikke eventuelle endringer i kopien vår originale xvil fortsatt ende opp med å krangle mer enn én gang om hvordan argumenter sendes i Java (selv blant erfarne utviklere). Men nå vet du nøyaktig hvordan det fungerer. Fortsett med det! :) For å forsterke det du lærte, foreslår vi at du ser en videoleksjon fra vårt Java-kurs
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION