CodeGym /Java blogg /Slumpmässig /Metoder i Java
John Squirrels
Nivå
San Francisco

Metoder i Java

Publicerad i gruppen
Hej igen! På förra lektionen bekantade vi oss med klasser och konstruktörer, och lärde oss att skapa våra egna. Idag kommer vi att bli bättre bekanta med Java Methods, en viktig del av klasser. En metoder i Java är en uppsättning kommandon som låter dig utföra en specifik operation i ett program. En metod är med andra ord en funktion; något som din klass kan göra. I andra programmeringsspråk kallas metoder ofta för "funktioner", men i Java är ordet "metod" vanligare. :) Om du kommer ihåg, i förra lektionen skapade vi enkla metoder för en kattklass , så att våra katter kunde säga jaja och hoppa:

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() och jump() är metoder i vår klass. Och att köra dessa metoder resulterar i följande konsolutgång:
Meow!
Pounce!
Våra metoder är ganska enkla: de matar helt enkelt ut text till konsolen. Men i Java har metoder en viktig uppgift: de utför åtgärder på ett objekts data. De ändrar objektets data, transformerar den, visar den och gör andra saker med den. Våra nuvarande metoder gör ingenting med Cat -objektets data. Låt oss titta på ett mer illustrativt exempel:

public class Truck {

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

    public int getVolume() {
        int volume = length * width * height;
        return volume;
    }
}
Här har vi till exempel en klass som representerar en lastbil . Semilastbilen har en längd, bredd, höjd och vikt (som vi kommer att behöva senare). I metoden getVolume() utför vi beräkningar, konverterar vårt objekts data till ett tal som representerar dess volym (vi multiplicerar längden, bredden och höjden). Detta nummer kommer att vara resultatet av metoden. Observera att metodens deklaration är skriven som public int getVolume . Det betyder att den här metoden måste returnera en int . Vi beräknade metodens returvärde, och nu måste vi returnera det till programmet som kallade vår metod. För att returnera en metods resultat i Java använder vi nyckelordet return. returvolym;

Java-metodparametrar

Vi kan skicka värden som kallas "argument" till en metod när vi anropar den. En metods deklaration innehåller en lista med variabler som berättar vilken typ och ordning av variabler som metoden kan acceptera. Denna lista kallas "metodparametrar". Vår lastbilsklasss metod getVolume() definierar för närvarande inga parametrar, så låt oss försöka utöka vårt lastbilsexempel . Skapa en ny klass som heter BridgeOfficer . Det här är en polis i tjänst vid en bro, som kontrollerar alla passerande lastbilar för att se om deras last överstiger den tillåtna vikten.

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 accepterar ett argument, ett lastbilsobjekt , och bestämmer om tjänstemannen kommer att tillåta lastbilen på bryggan eller inte. Inuti metoden är logiken enkel nog: om lastbilens vikt överstiger det maximalt tillåtna, returnerar metoden false . Den måste hitta en annan väg :( Om vikten är mindre än eller lika med maxgränsen kan den passera, och metoden returnerar sant. Om du inte helt förstår fraserna "retur" eller "metoden returnerar ett värde" ännu, låt oss ta en paus från programmering och överväga dem med ett enkelt exempel från det verkliga livet. :) Låt oss säga att du blir sjuk och stannar hemma från jobbet i några dagar. Du går till redovisningsavdelningen med din läkarlapp, eftersom sjukskrivning ska betalas ut. Om vi ​​jämför denna situation med metoder, så har revisorn en lönSickLeave()metod. Du skickar ett läkarintyg som ett argument till denna metod (utan den fungerar inte metoden och du får inte betalt!). Sedan görs de nödvändiga beräkningarna inuti metoden med hjälp av din anteckning (revisorn använder den för att beräkna hur mycket företaget ska betala dig), och resultatet av ditt arbete (en summa pengar) returneras till dig. Vårt program fungerar på liknande sätt. Den anropar en metod, skickar data till den och får till slut ett resultat. Här är vårt BridgeOfficer- programs main() -metod:

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 skapar två lastbilar med laster på 10 000 och 20 000. Och bron där officeren arbetar har en maxvikt på 15 000. Programmet anropar metoden officer.checkTruck(first) . Metoden beräknar allt och returnerar sedan true , som programmet sedan sparar till i den booleska variabeln canFirstTruckGo . Nu kan du göra vad du vill med den (precis som du kan med pengarna som revisorn gav dig). I slutet av dagen, koden

boolean canFirstTruckGo = officer.checkTruck(first);
kokar ner till

boolean canFirstTruckGo =  true;
Här är en mycket viktig punkt: retursatsen returnerar inte bara metodens returvärde, den stoppar också metoden från att köras! Alla koder som kommer efter retursatsen kommer inte att exekveras!

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!");
    }
}
Handläggarens kommentarer kommer inte att visas, eftersom metoden redan har returnerat ett resultat och avslutats! Programmet återgår till platsen där metoden anropades. Du behöver inte se upp för detta: Java-kompilatorn är smart nog att generera ett fel när du försöker skriva kod efter en retursats .

Avengers: Parameter War

Det finns situationer då vi vill ha flera sätt att anropa en metod. Varför inte skapa vår egen artificiella intelligens? Amazon har Alexa, Apple har Siri, så varför skulle vi inte ha en? :) I filmen Iron Man skapar Tony Stark sin egen otroliga artificiella intelligens, Jarvis. Låt oss hylla den fantastiska karaktären och namnge vår AI till hans ära. :) Det första vi behöver göra är att lära Jarvis att säga hej till folk som kommer in i rummet (det skulle vara konstigt om ett sådant fantastiskt intellekt visade sig vara oartigt).

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");
    }
}
Konsolutgång:
Good evening, Tony Stark. How are you?
Mycket bra! Jarvis kan nu välkomna gäster. Naturligtvis kommer det oftare än inte att vara hans mästare, Tony Stark. Men tänk om han inte kommer ensam! Vår sayHi() -metod accepterar bara ett argument. Så den kan bara hälsa på en person som kommer in i rummet och ignorerar den andra. Inte särskilt artig, håller du inte med? :/

Java-metod överbelastning

I det här fallet kan vi lösa problemet genom att helt enkelt skriva 2 metoder med samma namn, men olika parametrar:

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?");
    }
}
Detta kallas metodöverbelastning. Metodöverbelastning gör att vårt program blir mer flexibelt och rymmer olika sätt att arbeta. Låt oss se över hur det fungerar:

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");
    }
}
Konsolutgång:
Good evening, Tony Stark. How are you?
Good evening, Tony Stark and Captain America. How are you?
Utmärkt, båda versionerna fungerade. :) Men vi löste inte problemet! Tänk om det är tre gäster? Vi skulle naturligtvis kunna överbelasta sayHi() -metoden igen, så att den accepterar tre gästnamn. Men det kan finnas 4 eller 5. Hela vägen till oändligheten. Finns det inte ett bättre sätt att lära Jarvis att hantera hur många namn som helst, utan att överbelasta sayHi() -metoden en miljon gånger? :/ Självklart finns det! Om det inte fanns, tror du att Java skulle vara det populäraste programmeringsspråket i världen? ;)

public void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ". How are you?");
    }
}
När ( String... names ) används som en parameter, indikerar det att en samling strängar kommer att skickas till metoden. Vi behöver inte ange i förväg hur många det kommer att bli, så nu är vår metod mycket mer flexibel:

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");
    }
}
Konsolutgång:
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?
En del kod här kommer att vara obekant för dig, men oroa dig inte för det. Det är enkelt i grunden: metoden tar varje namn i tur och ordning och hälsar varje gäst välkomna! Dessutom kommer det att fungera med valfritt antal passerade strängar! Två, tio, till och med tusen — metoden kommer att fungera korrekt med hur många gäster som helst. Mycket bekvämare än att överbelasta metoden för alla möjligheter, tycker du inte? :) Här är en annan viktig punkt: ordningen på argumenten spelar roll! Låt oss säga att vår metod tar en sträng och ett nummer:

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!
    }
}
Om personklassens sayYourAge- metod tar en sträng och ett nummer som indata, måste programmet skicka dem i den specifika ordningen ! Om vi ​​skickar dem i en annan ordning kommer kompilatorn att generera ett fel och personen kommer inte att kunna säga sin ålder. Förresten, konstruktörer, som vi behandlade i förra lektionen, är också metoder! Du kan också överbelasta dem (dvs skapa flera konstruktörer med olika uppsättningar av parametrar) och ordningen på skickade argument är fundamentalt viktig för dem också. De är riktiga metoder! :)

Återigen angående parametrar

Japp, förlåt, vi är inte klara med dem än. :) Ämnet som vi ska studera nu är väldigt viktigt. Det finns 90 % chans att du kommer att bli tillfrågad om detta vid varje framtida intervju! Låt oss prata om att överföra argument till metoder. Tänk på ett enkelt exempel:

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 två metoder. De tar båda siffran som representerar det aktuella året som en input, och antingen ökar eller minskar dess värde (beroende på om vi vill gå till det förflutna eller framtiden). Men som du kan se från konsolutgången fungerar inte metoden! Konsolutgång:
What year is it?
2018
How about now?
2018
Vi skickade variabeln currentYear till metoden goToPast() , men dess värde ändrades inte. Vi var 2018, och här har vi stannat. Men varför? :/ Eftersom primitiver i Java skickas till metoder efter värde. Vad betyder det? När vi anropar metoden goToPast() och skickar int -variabeln currentYear (=2018) till den, får metoden inte själva currentYear -variabeln utan snarare en kopia av den. Naturligtvis är värdet på denna kopia också 2018, men eventuella ändringar av kopian påverkar inte vår ursprungliga nuvarandeYear -variabel på något sätt! Låt oss göra vår kod mer tydlig och se vad som händer 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);
    }
}
Konsolutgång:
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
Detta visar tydligt att variabeln som skickas till goToPast() -metoden bara är en kopia av currentYear . Och att ändra kopian påverkar inte det "original" värdet. "Passera genom referens" betyder raka motsatsen. Låt oss träna på katter! Jag menar, låt oss se hur det ser ut att gå förbi med hjälp av ett kattexempel. :)

public class Cat {

    int age;

    public Cat(int age) {
        this.age = age;
    }
}
Nu kommer vi med hjälp av vår tidsmaskin att skicka Smudge , världens första tidsresande katt, in i det förflutna och i framtiden! Låt oss modifiera TimeMachine- klassen så att den fungerar med Cat- objekt;

public class TimeMachine {

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

    public void goToPast(Cat cat) {
        cat.age -= 10;
    }    
}
Nu ändrar metoderna inte bara det godkända numret. Snarare ändrar de den specifika kattens åldersfält . Du kommer ihåg att detta inte fungerade för oss med primitiver, eftersom det ursprungliga numret inte ändrades. Låt oss se vad som kommer att hända!

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);
}
Konsolutgång:
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! Nu gjorde metoden något annat: vår katt åldrades drastiskt, men sedan blev den ung igen! :) Låt oss försöka ta reda på varför. Till skillnad från exemplet med primitiver, när objekt skickas till en metod skickas de genom referens. En referens till det ursprungliga smudge -objektet skickades till metoden changeAge() . Så när vi ändrar smudge.age inuti metoden hänvisar vi till samma minnesområde där vårt objekt är lagrat. Det är en referens till samma Smudge som vi skapade från början. Detta kallas "passera förbi"! Men allt med referenser är inte så lätt. :) Låt oss försöka ändra vårt exempel:

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);
    }
}
Konsolutgång:
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 fungerar inte igen! О_О Låt oss ta reda på vad som hände. :) Det har allt att göra med goToPast / goToFuture -metoderna och hur referenser fungerar. Nu, din uppmärksamhet, snälla! Detta är det viktigaste att förstå om hur referenser och metoder fungerar. Faktum är att när vi anropar goToFuture(Cat cat) -metoden, är det en kopia av referensen till kattobjektet som passeras, inte referensen i sig. Således, när vi skickar ett objekt till en metod, finns det två referenser till objektet. Detta är mycket viktigt för att förstå vad som händer. Det är just därför kattens ålder inte förändrades i vårt senaste exempel. I det föregående exemplet, när vi ändrade åldern, tog vi helt enkelt referensen som skickades till goToFuture()metod och använde den för att hitta objektet i minnet och ändra dess ålder ( cat.age += 10 ) . Men nu, inuti goToFuture() -metoden, skapar vi ett nytt objekt ( cat = new Cat(cat.age) ), och detta objekt tilldelas samma referenskopia som skickades till metoden. Som ett resultat:
  • Den första referensen ( Cat kladd = ny katt (5) ) pekar på den ursprungliga katten (med 5 års ålder)
  • Efter det, när vi skickade cat-variabeln goToPast() -metoden och tilldelade den ett nytt objekt, kopierades referensen.
Och detta förde oss till det slutliga resultatet: två referenser som pekar på två olika objekt. Men vi ändrade bara åldern på en av dem (den som skapades i metoden).

cat.age += 10;
Och naturligtvis, i main() -metoden kan vi se på konsolen att kattens ålder, smudge.age , inte har ändrats. Smudge är trots allt en referensvariabel som fortfarande pekar på det gamla, ursprungliga objektet med åldern 5, och vi gjorde ingenting med det objektet. Alla våra åldersförändringar utfördes på det nya objektet. Så det visar sig att objekt skickas till metoder genom referens. Kopior av objekt skapas aldrig automatiskt. Om du skickar ett kattobjekt till en metod och ändrar dess ålder kommer du att ändra dess ålder. Men referensvariabler kopieras när man tilldelar värden och/eller anropar metoder! Låt oss upprepa här vad vi sa om att överföra primitiver: "När vi anropar metoden changeInt() och skickar int .variabel x (=15) , metoden får inte själva variabeln x , utan snarare en kopia av den. Därför påverkar inte alla ändringar som görs i kopian vårt ursprungliga xKommer fortfarande att bråka mer än en gång om hur argument skickas i Java (även bland erfarna utvecklare). Men nu vet du exakt hur det fungerar. Fortsätt så! :) För att förstärka det du lärde dig föreslår vi att du tittar på en videolektion från vår Java-kurs
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION