CodeGym /Java блог /Случаен /Методи в Java
John Squirrels
Ниво
San Francisco

Методи в Java

Публикувано в групата
Здравей отново! В последния урок се запознахме с класове и конструктори и се научихме How да създаваме свои собствени. Днес ще се запознаем по-добре с методите на Java, съществена част от класовете. Методите в Java са набор от команди, които ви позволяват да извършите специфична операция в програма. С други думи, методът е функция; нещо, което вашият клас може да направи. В други езици за програмиране методите често се наричат ​​„функции“, но в Java думата „метод“ е по-често срещана. :) Ако си спомняте, в последния урок създадохме прости методи за клас Cat , така че нашите котки да могат да казват мяу и да скачат:

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() и jump() са методи на нашия клас. И изпълнението на тези методи води до следния конзолен изход:
Meow!
Pounce!
Нашите методи са доста прости: те просто извеждат текст към конзолата. Но в Java методите имат важна задача: те извършват действия върху данните на обекта. Те променят данните на обекта, трансформират го, показват го и правят други неща с него. Текущите ни методи не правят нищо с данните на обекта Cat . Нека да разгледаме един по-илюстративен пример:

public class Truck {

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

    public int getVolume() {
        int volume = length * width * height;
        return volume;
    }
}
Например, тук имаме клас, представляващ камион . Полукамионът има дължина, ширина, височина и тегло (което ще ни трябва по-късно). В метода getVolume() извършваме изчисления, преобразувайки данните на нашия обект в число, представляващо неговия обем (умножаваме дължината, ширината и височината). Това число ще бъде резултатът от метода. Имайте предвид, че декларацията на метода е написана като public int getVolume . Това означава, че този метод трябва да върне int . Изчислихме върнатата стойност на метода и сега трябва да я върнем на програмата, която извика нашия метод. За да върнем резултат от метод в Java, използваме ключовата дума return. обратен обем;

Параметри на метода на Java

Можем да предадем стойности, наречени „аргументи“, на метод, когато го извикваме. Декларацията на метода включва списък от променливи, които ни казват типа и реда на променливите, които методът може да приеме. Този списък се нарича "параметри на метода". Методът getVolume() на нашия клас Truck в момента не дефинира ниHowви параметри, така че нека опитаме да разширим нашия пример за камион. Създайте нов клас, наречен BridgeOfficer . Това е дежурен полицай на мост, който проверява всички преминаващи камиони дали товарът им надвишава разрешеното тегло.

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 приема един аргумент, обект Truck , и определя дали служителят ще допусне камиона на моста or не. Вътре в метода логиката е достатъчно проста: ако теглото на камиона надвишава максимално допустимото, тогава методът връща false . Ще трябва да намери друг път :( Ако теглото е по-малко or равно на максимума, може да премине и методът връща true. Ако все още не разбирате напълно фразите „връщане“ or „методът връща стойност“, нека си починем от програмирането и ги разгледаме, използвайки прост пример от реалния живот. :) Да кажем, че се разболееш и си останеш вкъщи от работа няколко дни. Отиваш в счетоводството с бележката от лекаря, защото уж се плащат болнични. Ако сравним тази ситуация с методите, тогава счетоводителят има paySickLeave ()метод. Прехвърляте лекарска бележка като аргумент на този метод (без нея методът няма да работи и няма да получите заплащане!). След това се правят необходимите изчисления вътре в метода, като се използва вашата бележка (счетоводителят я използва, за да изчисли колко трябва да ви плати компанията) и резултатът от вашата работа (парична сума) ви се връща. Нашата програма работи по подобен начин. Той извиква метод, предава му данни и в крайна сметка получава резултат. Ето метода main() на нашата програма BridgeOfficer :

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);
}
Създаваме два камиона с товари от 10 000 и 20 000. А мостът, на който работи офицерът, е с максимално тегло 15 000. Програмата извиква метода officer.checkTruck(first) . Методът изчислява всичко и след това връща true , което след това програмата записва в булевата променлива canFirstTruckGo . Сега можете да правите Howвото искате с него (точно Howто можете с парите, които счетоводителят ви е дал). В края на деня codeът

boolean canFirstTruckGo = officer.checkTruck(first);
се свежда до

boolean canFirstTruckGo =  true;
Ето един много важен момент: операторът return не просто връща върнатата стойност на метода, но също така спира изпълнението на метода! Всеки code, който идва след оператора return , няма да бъде изпълнен!

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!");
    }
}
Коментарите на служителя няма да бъдат показани, защото методът вече е върнал резултат и е прекратен! Програмата се връща на мястото, където е извикан методът. Не е нужно да следите за това: компилаторът на Java е достатъчно умен, за да генерира грешка, когато се опитате да напишете code след оператор за връщане .

Отмъстителите: Война с параметри

Има ситуации, когато ще искаме няколко начина за извикване на метод. Защо не създадем собствен изкуствен интелект? Amazon има Alexa, Apple има Siri, така че защо да не имаме и ние? :) Във филма Железният човек Тони Старк създава свой собствен невероятен изкуствен интелект Джарвис. Нека отдадем почит на този страхотен герой и назовем нашия AI в негова чест. :) Първото нещо, което трябва да направим, е да научим Джарвис да поздравява хората, които влизат в стаята (би било странно, ако такъв невероятен интелект се окаже неучтив).

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");
    }
}
Конзолен изход:
Good evening, Tony Stark. How are you?
Много добре! Джарвис вече може да посреща гости. Разбира се, по-често това ще бъде неговият господар Тони Старк. Но Howво като не дойде сам! Нашият метод sayHi() приема само един аргумент. И така може да поздрави само един човек, влизащ в стаята, и ще игнорира другия. Не е много учтиво, не сте ли съгласни? :/

Претоварване на Java метод

В този случай можем да решим проблема, като просто напишем 2 метода с едно и също име, но различни параметри:

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?");
    }
}
Това се нарича претоварване на метода. Претоварването на методите позволява на нашата програма да бъде по-гъвкава и да побира различни начини на работа. Нека прегледаме How работи:

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");
    }
}
Конзолен изход:
Good evening, Tony Stark. How are you?
Good evening, Tony Stark and Captain America. How are you?
Отлично, и двете версии работят. :) Но не решихме проблема! Ами ако гостите са трима? Можем, разбира се, да претоварим метода sayHi() отново, така че да приема три имена на гости. Но може да има 4 or 5. Чак до безкрайност. Няма ли по-добър начин да научите Джарвис да борави с произволен брой имена, без да претоварвате метода sayHi() мorон пъти? :/ Разбира се, че има! Ако го нямаше, мислите ли, че Java щеше да е най-популярният език за програмиране в света? ;)

public void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ". How are you?");
    }
}
Когато ( String... names ) се използва като параметър, това показва, че колекция от низове ще бъде предадена на метода. Не е нужно да уточняваме предварително колко ще бъдат, така че сега нашият метод е много по-гъвкав:

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");
    }
}
Конзолен изход:
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?
Някои codeове тук ще ви бъдат непознати, но не се притеснявайте за това. В основата си е прост: методът взема всяко име на свой ред и поздравява всеки гост! Освен това ще работи с произволен брой предадени низове! Двама, десет, дори хиляда - методът ще работи правилно с произволен брой гости. Много по-удобно от претоварването на метода за всички възможности, не мислите ли? :) Ето още един важен момент: редът на аргументите има meaning! Да кажем, че нашият метод приема низ и число:

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!
    }
}
Ако методът sayYourAge на класа Person приема низ и число като входове, тогава програмата трябва да ги предаде в този конкретен ред! Ако ги подадем в различен ред, компилаторът ще генерира грешка и човекът няма да може да каже възрастта си. Между другото, конструкторите, които разгледахме в миналия урок, също са методи! Можете също така да ги претоварите (т.е. да създадете няколко конструктора с различни набори от параметри) и редът на предаваните аргументи също е фундаментално важен за тях. Това са истински методи! :)

Отново относно параметрите

Да, съжаляваме, още не сме приключor с тях. :) Темата, която сега ще изучаваме е много важна. Има 90% шанс да ви попитат за това на всяко следващо интервю! Нека поговорим за предаването на аргументи към методите. Помислете за прост пример:

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);
    }
}
Машината на времето има два метода. И двамата приемат числото, представляващо текущата година като вход, и увеличават or намаляват стойността му (в зависимост от това дали искаме да отидем в миналото or в бъдещето). Но, Howто можете да видите от изхода на конзолата, методът не работи! Конзолен изход:
What year is it?
2018
How about now?
2018
Предадохме променливата currentYear на метода goToPast() , но стойността й не се промени. Бяхме през 2018 г. и останахме тук. Но защо? :/ Тъй като примитивите в Java се предават на методи по стойност. Какво означава това? Когато извикаме метода goToPast() и му предадем int променливата currentYear (=2018) , методът не получава самата променлива currentYear , а по-скоро нейно копие. Разбира се, стойността на това копие също е 2018, но всички промени в копието не засягат нашата оригинална променлива currentYear по ниHowъв начин! Нека направим нашия code по-ясен и гледаме Howво се случва с 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);
    }
}
Конзолен изход:
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
Това ясно показва, че променливата, предадена на метода goToPast() , е само копие на currentYear . И промяната на копието не засяга "оригиналната" стойност. „Предаване по препратка“ означава точно обратното. Да тренираме върху котки! Искам да кажа, нека видим How изглежда преминаването по референция, използвайки пример с котка. :)

public class Cat {

    int age;

    public Cat(int age) {
        this.age = age;
    }
}
Сега с помощта на нашата машина на времето ще изпратим Smudge , първата в света котка, пътуваща във времето, в миналото и бъдещето! Нека модифицираме класа TimeMachine , така че да работи с Cat обекти;

public class TimeMachine {

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

    public void goToPast(Cat cat) {
        cat.age -= 10;
    }    
}
Сега методите не просто променят предаденото число. По-скоро те променят това конкретно поле за възрастта на Cat . Спомняте си, че това не работи за нас с примитиви, защото оригиналното число не се промени. Да видим Howво ще стане!

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);
}
Конзолен изход:
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
Еха! Сега методът направи нещо различно: нашата котка остаря драстично, но след това отново стана млада! :) Нека се опитаме да разберем защо. За разлика от примера с примитивите, когато обектите се предават на метод, те се предават по референция. Препратка към оригиналния обект на петна беше предадена на метода changeAge() . Така че, когато променим smudge.age вътре в метода, ние препращаме към същата област от паметта, където се съхранява нашият обект. Това е препратка към същото петно, което създадохме първоначално. Това се нарича "предаване по препратка"! Не всичко с референциите обаче е толкова лесно. :) Нека опитаме да променим нашия пример:

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);
    }
}
Конзолен изход:
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
Пак не става! О_О Нека да разберем Howво се е случило. :) Има всичко общо с методите goToPast / goToFuture и How работят препратките. А сега вашето внимание, моля! Това е най-важното нещо, което трябва да разберете за това How работят справките и методите. Факт е, че когато извикаме метода goToFuture(Cat cat) , се предава копие на препратката към обекта cat, а не самата препратка. По този начин, когато предаваме обект на метод, има две препратки към обекта. Това е много важно за разбирането на случващото се. Ето защо възрастта на котката не се е променила в последния ни пример. В предишния пример, когато променяхме възрастта, просто взехме препратката, предадена на goToFuture()метод и го използва, за да намери обекта в паметта и да промени възрастта му ( cat.age += 10 ). Но сега, вътре в метода goToFuture() , ние създаваме нов обект ( cat = new Cat(cat.age) ) и на този обект се присвоява същото референтно копие, което беше предадено на метода. Като резултат:
  • Първата препратка ( Cat smudge = new Cat (5) ) сочи към оригиналната котка (на възраст 5)
  • След това, когато предадохме на променливата cat метода goToPast() и му присвоихме нов обект, препратката беше копирана.
И това ни доведе до крайния резултат: две препратки, сочещи към два различни обекта. Но променихме възрастта само на един от тях (този, създаден в метода).

cat.age += 10;
И разбира се, в метода main() можем да видим на конзолата, че възрастта на котката, smudge.age , не се е променила. В края на краищата smudge е референтна променлива, която все още сочи към стария, оригинален обект на 5-годишна възраст и ние не направихме нищо с този обект. Всички наши възрастови промени бяха извършени на новия обект. И така, оказва се, че обектите се предават на методи по референция. Копия на обекти никога не се създават автоматично. Ако предадете котка обект на метод и промените възрастта му, вие ще промените възрастта му. Но референтните променливи се копират при присвояване на стойности и/or извикване на методи! Нека повторим тук Howво казахме за предаването на примитиви: „Когато извикаме метода changeInt() и предадем intпроменлива x (=15) , методът не получава самата променлива x , а по-скоро нейно копие. Следователно, всички промени, напequalsи в копието, не засягат оригиналния xВсе пак ще се стигне до спорове повече от веднъж за това How се предават аргументи в Java (дори сред опитни разработчици). Но сега знаете точно How работи. Продължавай така! :) За да затвърдите наученото, ви предлагаме да гледате видео урок от нашия курс по Java
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION