CodeGym /Java Blog /Toto sisi /Java 中的方法
John Squirrels
等級 41
San Francisco

Java 中的方法

在 Toto sisi 群組發布
再一次問好!在上一課中,我們熟悉了類和構造函數,並學習瞭如何創建我們自己的類和構造函數。今天我們將更好地熟悉 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 方法參數

我們可以在調用方法時將稱為“參數”的值傳遞給方法。一個方法的聲明包括一個變量列表,它告訴我們該方法可以接受的變量的類型和順序。該列表稱為“方法參數”。我們的Truck類的getVolume()方法目前沒有定義任何參數,所以讓我們嘗試擴展我們的卡車示例。創建一個名為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()方法。您將醫生的證明作為參數傳遞給此方法(沒有它,該方法將不起作用,您也不會得到報酬!)。然後使用你的筆記在方法內部進行必要的計算(會計師用它來計算公司應該付給你多少錢),並將你的工作結果(一筆錢)返回給你。我們的程序以類似的方式工作。它調用一個方法,將數據傳遞給它,並最終接收一個結果。這是我們的BridgeOfficer程序的main()方法:

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 的卡車。而軍官工作的橋,最大承重為15000。該程序調用officer.checkTruck(first)方法。該方法計算所有內容,然後返回true,然後程序將其保存到布爾變量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, you're overweight!");
    } else {
        return true;
        System.out.println("Everything looks good, go ahead!");
    }
}
不會顯示官員的評論,因為該方法已經返回結果並終止!程序返回調用方法的地方。您不必注意這一點:Java 編譯器足夠聰明,可以在您嘗試在return語句之後編寫代碼時生成錯誤。

復仇者聯盟:參數戰爭

在某些情況下,我們需要多種調用方法的方式。為什麼不創造我們自己的人工智能?亞馬遜有 Alexa,蘋果有 Siri,那麼我們為什麼不應該有一個呢?:) 在電影鋼鐵俠中,托尼·斯塔克創造了他自己不可思議的人工智能賈維斯。讓我們向這位了不起的人物致敬,並以他的名字命名我們的 AI。:) 我們需要做的第一件事是教 Jarvis 向進入房間的人打招呼(如果這樣一個驚人的智慧竟然是不禮貌的,那將是奇怪的)。

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?
非常好!賈維斯現在可以歡迎客人了。當然,更多時候是他的主人托尼·斯塔克。可萬一他一個人不來呢!我們的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?");
    }
}
這稱為方法重載。方法重載使我們的程序更加靈活,並適應各種工作方式。讓我們回顧一下它是如何工作的:

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 或 5 個。一直到無窮大。有沒有更好的方法教 Jarvis 處理任意數量的名字,而不用重載sayHi()方法一百萬次?:/ 當然有!如果沒有,您認為 Java 會成為世界上最流行的編程語言嗎?;)

public void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ". How are you?");
    }
}
當 ( String... names ) 用作參數時,表示將向該方法傳遞一個 String 集合。我們不必事先指定會有多少,所以現在我們的方法更加靈活:

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?
這裡的一些代碼你會很陌生,但不要擔心。它的核心很簡單:該方法依次獲取每個名字並問候每位客人!另外,它可以處理任意數量的傳遞字符串!兩人、十人,甚至一千人——這種方法對任何數量的客人都適用。比為所有可能性重載方法更方便,你不覺得嗎?:) 這是另一個重點:參數的順序很重要!假設我們的方法接受一個字符串和一個數字:

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!
    }
}
如果Person類的sayYourAge方法接受一個字符串和一個數字作為輸入,那麼程序必須按照特定的順序傳遞它們!如果我們以不同的順序傳遞它們,編譯器將產生一個錯誤並且這個人將無法說出他的年齡。順便說一句,我們在上一課中介紹的構造函數也是方法!您還可以重載它們(即創建多個具有不同參數集的構造函數)並且傳遞參數的順序對它們來說也很重要。它們是真正的方法!:)

再次關於參數

是的,抱歉,我們還沒有完成它們。:) 我們現在要研究的主題非常重要。有 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);
    }
}
時間機器有兩種方法。它們都將代表當前年份的數字作為輸入,然後增加或減少它的值(取決於我們是想回到過去還是未來)。但是,正如您從控制台輸出中看到的那樣,該方法不起作用!控制台輸出:
What year is it?
2018
How about now?
2018
我們將currentYear變量傳遞給goToPast()方法,但它的值沒有改變。我們在 2018 年,我們一直在這裡。但為什麼?:/ 因為 Java 中的原語是按值傳遞給方法的。這意味著什麼?當我們調用goToPast()方法並將int變量currentYear (=2018)傳遞給它時,該方法不會獲取currentYear變量本身,而是獲取它的副本。當然,這個副本的值也是 2018,但是對副本的任何更改都不會以任何方式影響我們原來的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 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的一個副本。並且更改副本不會影響“原始”值。“按引用傳遞”的意思恰恰相反。讓我們在貓身上練習吧!我的意思是,讓我們使用 cat 示例看看按引用傳遞是什麼樣的。:)

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;
    }    
}
現在這些方法不只是改變傳遞的數字。相反,他們更改了特定的Catage字段。你會記得這對我們的基元不起作用,因為原始數字沒有改變。讓我們看看會發生什麼!

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時,我們引用的是存儲對象的同一內存區域。它是對我們最初創建的同一個 Smudge 的引用。這就是所謂的“通過引用”!然而,並非所有帶有參考文獻的東西都那麼容易。:) 讓我們嘗試改變我們的例子:

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
又不行了!О_О讓我們弄清楚發生了什麼。:) 它與goToPast / goToFuture方法以及引用的工作方式有關。現在,請注意!這是理解引用和方法如何工作的最重要的事情。事實上,當我們調用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 的舊的原始對象,而我們沒有對該對像做任何事情。我們所有的年齡變化都是在新對像上進行的。 因此,事實證明對像是通過引用傳遞給方法的。永遠不會自動創建對象的副本。如果將貓對像傳遞給方法並更改其年齡,則將更改其年齡。但是在賦值和/或調用方法時會復制引用變量!讓我們在這裡重複我們所說的關於傳遞原語的話:“當我們調用changeInt()方法並傳遞intvariable x (=15),該方法不會獲取x變量本身,而是獲取它的副本。因此,對副本所做的任何更改都不會影響我們的原始x您最終還是會不止一次地爭論 Java 中參數的傳遞方式(即使是在有經驗的開發人員之間)。但是,現在您確切地知道它是如何工作的。繼續努力吧!:) 為了鞏固您所學的知識,我們建議您觀看我們的 Java 課程中的視頻課程
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION