JavaRush /Java Blog /Random-TW /方法、它們的參數、交互作用和重載

方法、它們的參數、交互作用和重載

在 Random-TW 群組發布
再一次問好!在上一課中,我們熟悉了類別和建構函數,並學習如何創建我們自己的類別和建構函數。 方法、它們的參數、交互作用和重載 - 1今天我們將仔細研究類別中不可或缺的一部分—方法。 方法是一組命令,允許您在程式中執行某些操作。換句話說,方法就是函數;你的班級可以做的事情。在其他程式語言中,方法通常被稱為“函數”,但在Java 中,“方法”這個詞變得更流行:) 在上一課中,如果你還記得的話,我們為Cat 類別創建了簡單的方法,以便我們的貓可以喵喵叫並跳躍:
public class Cat {

    String name;
    int age;

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

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

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

        barsik.sayMeow();
        barsik.jump();
    }
}
sayMeow()jump()是我們班的方法。他們的工作結果是輸出到控制台:
Мяу!
Прыг-скок!
我們的方法非常簡單:它們只是將文字列印到控制台。但在 Java 中,方法有一個主要任務 -它們必須對物件的資料執行操作。更改物件資料的值、對其進行轉換、將其輸出到控制台或對其執行其他操作。我們目前的方法不會對物件的資料執行任何操作Cat。讓我們來看一個更清楚的例子:
public class Truck {

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

    public int getVolume() {
        int volume = length * width * height;
        return volume;
    }
}
例如,我們有一個代表卡車的類別 - Truck。卡車拖車有長度、寬度、高度以及重量(稍後需要)。在這個方法中,getVolume()我們執行計算 - 將物件的資料轉換為表示體積的數字(我們乘以長度、寬度和高度)。這是該方法的結果數字。請注意 - 在方法的描述中它是這樣寫的public int getVolume。這意味著該方法的結果必須是形式為的數字int。我們已經計算了該方法的結果,現在我們必須將其傳回給呼叫該方法的程式。若要傳回 Java 中方法的結果,請使用關鍵字return
return volume;

方法參數

方法可以接受值作為輸入,這些值稱為「方法參數」。我們目前getVolume()類別中的方法Truck不接受任何參數,因此讓我們嘗試用卡車來擴展範例。讓我們建立一個新類別 - 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,並確定官員是否允許卡車上橋。該方法內部的邏輯非常簡單:如果卡車的重量超過允許的最大重量,則該方法將返回false。你就得另尋路了:(如果權重小於或等於最大值,你就可以通過,方法返回true。如果你還沒有完全理解“返回”、“方法返回一個值”這句話” - 讓我們暫時放下編程,用現實生活中的一個簡單例子來看看這個問題:) 假設您生病了,並且已經好幾天沒有上班了。你帶著病假來到會計部門,你必須支付病假費用。如果用方法來比喻的話,會計師就有方法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 number 1! May I pass, officer?");
    boolean canFirstTruckGo = officer.checkTruck(first);
    System.out.println(canFirstTruckGo);

    System.out.println();

    System.out.println("Truck number 2! May I?");
    boolean canSecondTruckGo = officer.checkTruck(second);
    System.out.println(canSecondTruckGo);
}
我們正在創建兩輛卡車,負載分別為 10,000 和 20,000。同時,人員執勤的橋樑的最大重量為 15,000。程式呼叫了 方法,該方法計算了所有內容並將結果傳回officer.checkTruck(first)給程式 - true,程式將其保存在變數中boolean canFirstTruckGo。現在他可以用它做任何他想做的事(就像你用你從會計師那裡收到的錢一樣)。最終程式碼
boolean canFirstTruckGo = officer.checkTruck(first);
歸結為
boolean canFirstTruckGo = true;
非常重要的一點:運算子return不僅傳回方法的結果,還終止其工作!return之後寫的所有程式碼都不會被執行!
public boolean checkTruck(Truck truck) {

    if (truck.weight > maxWeight) {
        return false;
        System.out.println("Turn around, overweight!");
    } else {
        return true;
        System.out.println("Alright, move on!");
    }
}
軍官所說的這句話不會輸出到控制台,因為該方法已經返回了結果並完成了它的工作!程式返回到呼叫該方法的地方。您自己不必擔心這一點 - 如果您嘗試在return.

復仇者聯盟:選拔之戰

在某些情況下,我們的程式需要多個選項來決定方法的工作方式。 我們為什麼不創造自己的人工智慧呢?Amazon 有Alexa,Yandex 有Alice,那為什麼我們會更差呢?:) 在有關鋼鐵人的電影中,托尼·斯塔克創造了自己傑出的人工智能- JARVIS 讓我們向這個精彩的角色致敬,並以他的名字命名我們的人工智慧:)我們必須教導賈維斯的第一件事是——向進入房間的人打招呼(如果如此偉大的智慧最終被證明是不禮貌的,那就太奇怪了)。
public class Jarvis {

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

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark");
    }
}
控制台輸出:
Добрый вечер, Тони Старк, How ваши дела?
偉大的!賈維斯知道如何迎接進來的人。當然,最常見的是他的主人——東尼史塔克。但他可能不會一個人來!我們的方法sayHi()只接受一個參數作為輸入。因此,他只能向其中一位來者打招呼,而忽略另一位。不太有禮貌,同意嗎?:/ 在這種情況下,為了解決這個問題,我們可以簡單地在類別中編寫兩個同名但參數不同的方法:
public class Jarvis {

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

    public void sayHi(String firstGuest, String secondGuest) {
        System.out.println("Good evening, " + firstGuest + ", " + secondGuest + ", How are you doing?");
    }
}
這稱為方法重載。重載使我們的計劃更加靈活並適應不同的工作選擇。讓我們檢查一下它是如何工作的:
public class Jarvis {

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

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

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark");
        jarvis.sayHi("Tony Stark", "Captain America");
    }
}
控制台輸出:
Добрый вечер, Тони Старк, How ваши дела?
Добрый вечер, Тони Старк, Капитан Америка, How ваши дела?
太棒了,兩個選擇都有效:)但是,我們沒有解決問題!如果有三個客人怎麼辦?當然,我們可以再次重載該方法sayHi()以接受三位客人的名字。但也可以有 4 或 5 個,以此類推,無止境。是否有另一種方法可以教 Jarvis 使用任意數量的名稱,而不需要一百萬個方法重載sayHi()?:/ 當然有!否則,Java 會成為世界上最受歡迎的程式語言嗎?;)
public void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ", How are you doing?");
    }
}
作為參數傳遞的記錄 ( String...names) 允許我們指示將一定數量的字串傳遞給該方法。我們沒有提前指定應該有多少個,因此我們方法的操作現在變得更加靈活:
public class Jarvis {

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

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
    }
}
控制台輸出:
Добрый вечер, Тони Старк, How ваши дела?
Добрый вечер, Капитан Америка, How ваши дела?
Добрый вечер, Черная Вдова, How ваши дела?
Добрый вечер, Халк, How ваши дела?
這裡的一些程式碼對您來說不熟悉,但不要介意。它的本質很簡單——該方法依次遍歷​​所有的名字並向每一位客人打招呼!此外,它適用於任意數量的傳輸線路!兩個、十個、甚至一千個——該方法對於任意數量的客人都可以可靠地工作。比對所有可能的選項進行重載要方便得多,您同意嗎?:) 另一個重要的一點:參數的順序很重要!假設我們的方法接受一個字串和一個數字作為輸入:
public class Man {

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

    public static void main(String[] args) {
        sayYourAge("My age - ", 33);
        sayYourAge(33, "My age - "); //error!
    }
}
如果sayYourAge類別方法Man接受字串和數字作為輸入,那麼這就是它們在程式中傳遞的順序!如果我們以不同的順序傳遞它們,編譯器將拋出錯誤,並且該人將無法說出他的年齡。順便說一句,我們在上一講介紹的構造函數也是方法!它們還可以重載(使用不同的參數集來建立多個建構函數),對於它們來說,傳遞參數的順序也非常重要。真正的方法!:)

再次關於參數

是的,是的,我們還沒有完成它們:)我們現在要考慮的主題非常重要。 有 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 = 2020;

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

        timeMachine.goToPast(currentYear);
        System.out.println("And now?");
        System.out.println(currentYear);
    }
}
時間機器有兩種方法。兩者都將代表當前年份的數字作為輸入,並增加或減少該值(取決於我們是想回到過去還是未來)。但是,從控制台輸出可以看出,該方法不起作用!控制台輸出:
Какой сейчас год?
2020
А сейчас?
2020
我們currentYear向方法傳遞了一個變量goToPast(),但它的值沒有改變。2020年依然如此。但為什麼?:/ 因為 Java 中的原語是按值傳遞給方法的。這是什麼意思?當我們呼叫一個方法goToPast()並將變數傳遞到那裡時int currentYear = 2020,進入該方法的不是變數本身currentYear,而是變數的副本。當然,這個副本的值也等於 2020,但是副本發生的所有更改都不會以任何方式影響我們的原始變數currentYear!讓我們讓程式碼更加詳細,看看會發生什麼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!");
        System.out.println("The currentYear value inside the goToPast method (at the beginning) = " + currentYear);
        currentYear = currentYear-10;
        System.out.println("The currentYear value inside the goToPast method (at the end) = " + currentYear);
    }

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

        System.out.println("What is the year at the very beginning of the program?");
        System.out.println(currentYear);

        timeMachine.goToPast(currentYear);
        System.out.println("What year is it now?");
        System.out.println(currentYear);
    }
}
控制台輸出:
Какой год в самом начале работы программы?
2020
Метод goToPast начал работу!
Значение currentYear внутри метода goToPast (в начале) = 2020
Значение currentYear внутри метода goToPast (в конце) = 2010
А сейчас Howой год?
2020
這清楚地表明傳遞給該方法的變數goToPast()只是副本currentYear。更改副本對「原件」的意思沒有影響。「透過引用傳遞」具有完全相反的意思。讓我們用貓來練習吧!我的意思是,讓我們以貓為例看看透過連結是什麼樣子:)
public class Cat {

    int age;

    public Cat(int age) {
        this.age = age;
    }
}
現在,在時間機器的幫助下,我們將把世界上第一個貓時間旅行者 Barsik 發射到過去和未來!讓我們更改類別,TimeMachine以便機器可以處理物件Cat
public class TimeMachine {

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

    public void goToPast(Cat cat) {
        cat.age -= 10;
    }
}
方法現在不僅更改傳遞的數字,還更改age特定物件的欄位Cat。就原語而言,正如您所記得的,我們沒有成功:原始數字沒有改變。讓我們看看這裡會發生什麼!
public static void main(String[] args) {

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

    System.out.println("How old is Barsik at the very beginning of the program?");
    System.out.println(barsik.age);

    timeMachine.goToFuture(barsik);
    System.out.println("And now?");
    System.out.println(barsik.age);

    System.out.println("Firs-sticks! Barsik has aged 10 years! Drive back quickly!");
    timeMachine.goToPast(barsik);
    System.out.println("Did it work? Have we returned the cat to its original age?");
    System.out.println(barsik.age);
}
控制台輸出:
Сколько лет Барсику в самом начале работы программы?
5
А теперь?
15
Елки-палки! Барсик постарел на 10 лет! Живо гони назад!
Получилось? Мы вернули коту его изначальный возраст?
5
哇!現在方法不同了:我們的貓突然變老了,然後看起來又年輕了!:) 讓我們試著找出原因。與基元的範例不同,在物件的情況下,對物件的參考將傳遞給方法。對原始物件的引用被傳遞goToFuture(barsik)給方法。因此,當我們更改內部方法時,我們存取的是儲存物件的記憶體區域。這是我們一開始創建的同一個 Barsik 的連結。這就是所謂的「透過引用傳遞」!然而,有了這些鏈接,一切就不那麼簡單了:)讓我們嘗試改變我們的例子: goToPast(barsik)barsikbarsik.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 barsik = new Cat(5);

        System.out.println("How old is Barsik at the very beginning of the program?");
        System.out.println(barsik.age);

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

        System.out.println("And if you try in the past?");
        timeMachine.goToPast(barsik);
        System.out.println(barsik.age);
    }
}
控制台輸出:
Сколько лет Барсику в самом начале работы программы?
5
Барсик отправился в будущее! Его возраст изменился?
5
А если попробовать в прошлое?
5
又不行了!O_O 讓我們弄清楚發生了什麼:) 這都是關於連結如何運作的方法goToPast/goToFuture和機制。 現在註意!這一點對於理解連結和方法如何運作是最重要的。事實上,當我們呼叫一個方法時,goToFuture(Cat cat)傳遞給它的並不是物件參考本身cat,而是這個引用的副本。 也就是說,當我們將一個物件傳遞給方法時,有兩個對該物件的參考。這對於理解正在發生的事情非常重要。畢竟,這就是為什麼我們的最後一個例子沒有改變貓的年齡。在前面更改年齡的範例中,我們只是在方法中獲取傳遞的引用goToFuture(),使用它在記憶體中找到物件並更改其年齡(cat.age += 10)。現在在方法中goToFuture()我們建立一個新對象
(cat = new Cat(cat.age)),
並且傳遞給該方法的相同複製連結被指派給該物件。因此:
  • 第一個連結 ( Cat barsik = new Cat(5)) 指向原來的貓(年齡為 5)
  • 當我們將變數傳遞cat給方法goToPast(Cat cat)並將其分配給新物件後,引用就被複製了。
之後,我們就得到了最終的情況:兩個連結指向兩個不同的物件。但我們只更改了其中一個的年齡 - 我們在方法內創建的年齡。
cat.age += 10;
當然,當我們在方法中將其輸出main()到控制台時barsik.age,我們看到它的年齡並沒有改變。畢竟barsik,這是一個引用變量,它仍然指向年齡為 5 的舊的原始對象,而該對象沒有發生任何事情。我們對年齡的所有操作都是在一個新物件上進行的。因此,事實證明物件是透過引用傳遞給方法的。物件的副本永遠不會自動建立。如果您將貓物件傳遞給方法並更改其年齡,它將成功更改。但是引用變數的值在賦值和/或呼叫方法時會被複製!讓我們在這裡重複一下關於傳遞原語的段落:「當我們呼叫一個方法changeInt()並將變數傳遞到那裡時int x = 15,進入該方法的不是變數本身x,而是它的副本。畢竟,副本中發生的所有更改都不會改變。”以任何方式影響我們的原始變數x。” 透過複製鏈接,一切都完全相同!您將 cat 物件傳遞給該方法。如果您對貓本身(即內存中的物件)執行某些操作,則所有更改都會成功完成 - 我們只有一個物件並且仍然擁有它。但是,如果在方法內部建立新物件並將其保存在引用變數(該變數是該方法的參數)中,那麼從現在開始我們就有兩個物件和兩個引用變數。就這樣!沒那麼容易,甚至可能要講好幾遍。但最主要的是你已經學會這個超重要的主題了。您經常會遇到關於 Java 中如何傳遞參數的爭論(即使在經驗豐富的開發人員之間)。現在您確切地知道它是如何工作的。繼續努力!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION