CodeGym /จาวาบล็อก /สุ่ม /วิธีการใน Java
John Squirrels
ระดับ
San Francisco

วิธีการใน Java

เผยแพร่ในกลุ่ม
สวัสดีอีกครั้ง! ในบทเรียนที่แล้ว เราได้ทำความคุ้นเคยกับคลาสและคอนสตรัคเตอร์ และเรียนรู้วิธีสร้างคลาสของเราเอง วันนี้เราจะมาทำความรู้จักกับ Java Methods ซึ่งเป็นส่วนสำคัญของคลาส เมธอดใน Java คือชุดคำสั่งที่อนุญาตให้คุณดำเนินการบางอย่างในโปรแกรม กล่าวอีกนัยหนึ่ง เมธอดคือฟังก์ชัน สิ่งที่ชั้นเรียนของคุณสามารถทำได้ ในภาษาโปรแกรมอื่น เมธอดมักเรียกว่า "ฟังก์ชัน" แต่ใน Java คำว่า "เมธอด" เป็นคำที่ใช้บ่อยกว่า :) หากคุณจำได้ ในบทเรียนที่แล้วเราได้สร้างวิธีการง่ายๆ สำหรับ ชั้นเรียน แมวเพื่อให้แมวของเราสามารถร้องเหมียวและกระโดดได้:

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()ของคลาสรถบรรทุกของเราไม่ได้กำหนดพารามิเตอร์ใดๆ ในขณะนี้ ดังนั้น มาลองขยายตัวอย่างรถบรรทุกของเรากัน สร้างคลาสใหม่ชื่อ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;
        }
    }
}
วิธีตรวจสอบรถบรรทุกยอมรับหนึ่งข้อโต้แย้ง วัตถุ รถบรรทุกและกำหนดว่าเจ้าหน้าที่จะอนุญาตให้รถบรรทุกขึ้นสะพานหรือไม่ ภายในเมธอด ตรรกะก็ง่ายพอ: หากน้ำหนักรถบรรทุกเกินค่าสูงสุดที่อนุญาต เมธอดจะส่งกลับค่าเท็จ มันจะต้องหาทางอื่น :( ถ้าน้ำหนักน้อยกว่าหรือเท่ากับสูงสุด ก็ผ่านไปได้ และวิธีการคืนค่าจริง. หากคุณยังไม่เข้าใจวลี "return" หรือ "the method returns a value" อย่างถ่องแท้ ลองพักจากการเขียนโปรแกรมและพิจารณาโดยใช้ตัวอย่างง่ายๆ จากชีวิตจริง :) สมมติว่าคุณป่วยและหยุดงานอยู่บ้านสักสองสามวัน คุณไปที่แผนกบัญชีพร้อมกับบันทึกแพทย์ของคุณ เพราะการลาป่วยควรได้รับค่าจ้าง หากเราเปรียบเทียบสถานการณ์นี้กับเมธอด นักบัญชีจะมี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(ตัวแรก) เมธอดจะคำนวณทุกอย่างแล้วคืนค่าtrueซึ่งโปรแกรมจะบันทึกไว้ในตัวแปรบูลีcanFirstTruckGo ตอนนี้คุณสามารถทำอะไรก็ได้ที่คุณต้องการ (เหมือนกับที่คุณทำได้ด้วยเงินที่นักบัญชีมอบให้คุณ) ในตอนท้ายของวันรหัส

boolean canFirstTruckGo = officer.checkTruck(first);
เดือดลงไป

boolean canFirstTruckGo =  true;
นี่คือจุดที่สำคัญมาก: return statement ไม่เพียงแค่ส่งคืนค่าที่ส่งคืนของเมธอดเท่านั้น แต่ยังหยุดการทำงานของเมธอดด้วย! รหัสใด ๆ ที่ตามมาหลังจาก คำสั่ง ส่งคืนจะไม่ถูกดำเนินการ!

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

เวนเจอร์ส: สงครามพารามิเตอร์

มีบางสถานการณ์ที่เราต้องการเรียกใช้เมธอดหลายวิธี ทำไมไม่สร้างปัญญาประดิษฐ์ของเราเอง? Amazon มี Alexa, Apple มี Siri แล้วทำไมเราจะไม่มีล่ะ :) ในภาพยนตร์เรื่อง Iron Man โทนี่ สตาร์กสร้างจาร์วิสปัญญาประดิษฐ์ที่น่าทึ่งของเขาเอง เรามายกย่องตัวละครที่ยอดเยี่ยมและตั้งชื่อ 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?
ดีมาก! Jarvis สามารถต้อนรับแขกได้แล้ว แน่นอนว่าโทนี่สตาร์คเจ้านายของเขาบ่อยกว่านั้น แต่ถ้าเขาไม่ได้มาคนเดียวล่ะ! เมธอด 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 ) เป็นพารามิเตอร์ แสดงว่าชุดของ Strings จะถูกส่งผ่านไปยังเมธอด เราไม่ต้องระบุล่วงหน้าว่าจะมีกี่รายการ ดังนั้นตอนนี้วิธีการของเราจึงยืดหยุ่นมากขึ้น:

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!
    }
}
ถ้า เมธอด sayYourAgeของคลาสPersonรับสตริงและตัวเลขเป็นอินพุต โปรแกรมจะต้องส่งผ่านตามลำดับเฉพาะนั้น! หากเราส่งตามลำดับที่แตกต่างกัน คอมไพเลอร์จะสร้างข้อผิดพลาดและบุคคลนั้นจะไม่สามารถบอกอายุของเขาได้ อย่างไรก็ตาม ตัวสร้างที่เรากล่าวถึงในบทเรียนที่แล้วก็เป็นวิธีการเช่นกัน! คุณยังสามารถโอเวอร์โหลดพวกมันได้ (เช่น สร้างคอนสตรัคเตอร์หลายตัวด้วยชุดพารามิเตอร์ที่แตกต่างกัน) และลำดับของอาร์กิวเมนต์ที่ส่งผ่านก็มีความสำคัญสำหรับพวกมันเช่นกัน เป็นวิธีการที่แท้จริง! :)

อีกครั้งเกี่ยวกับพารามิเตอร์

ใช่ ขออภัย เรายังจัดการกับพวกเขาไม่เสร็จ :) หัวข้อที่เราจะเรียนตอนนี้สำคัญมาก มีโอกาส 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
เราส่ง ตัวแปร ปีปัจจุบันไปยัง เมธอด goToPast()แต่ค่าไม่เปลี่ยนแปลง เราอยู่ในปี 2561 และเราเคยพักที่นี่ แต่ทำไม? :/ เนื่องจาก primitives ใน Java ถูกส่งผ่านไปยัง method ตามค่า นั่นหมายความว่าอย่างไร? เมื่อเราเรียก เมธอด goToPast()และส่งตัวแปรint currentYear (=2018)ไป เมธอดจะไม่ได้รับ ตัวแปร ปีปัจจุบันแต่เป็นสำเนาของมัน แน่นอนว่ามูลค่าของสำเนานี้คือปี 2018 เช่นกัน แต่การเปลี่ยนแปลงใด ๆ ที่ทำกับสำเนาจะไม่ส่งผลต่อ ตัวแปร ปีปัจจุบัน ดั้งเดิมของเรา แต่อย่างใด! มาทำให้รหัสของเราชัดเจนยิ่งขึ้นและดูว่าเกิดอะไรขึ้นกับปีปัจจุบัน:

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เท่านั้น และการเปลี่ยนสำเนาจะไม่ส่งผลต่อค่า "ต้นฉบับ" "ผ่านการอ้างอิง" หมายถึงตรงกันข้าม มาฝึกแมวกันเถอะ! ฉันหมายความว่า เรามาดูกันว่าการผ่านการอ้างอิงมีลักษณะอย่างไรโดยใช้ตัวอย่างแมว :)

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;
    }    
}
ตอนนี้เมธอดไม่เพียงแค่เปลี่ยนตัวเลขที่ผ่านไปเท่านั้น แต่เปลี่ยนฟิลด์อายุของแมว เฉพาะนั้น คุณจะจำได้ว่าวิธีนี้ใช้ไม่ได้กับตัวเลขดั้งเดิม เพราะจำนวนดั้งเดิมไม่ได้เปลี่ยนแปลง มาดูกันว่าจะเกิดอะไรขึ้น!

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
ว้าว! ตอนนี้วิธีการทำบางอย่างแตกต่างออกไป: แมวของเราแก่ลงอย่างมาก แต่แล้วมันก็กลับเป็นหนุ่มอีกครั้ง! :) ลองหาสาเหตุกัน ไม่เหมือนกับตัวอย่างที่มีพื้นฐาน เมื่อออบเจกต์ถูกส่งผ่านไปยังเมธอดที่ออบเจกต์นั้นถูกส่งผ่านโดยการอ้างอิง การอ้างอิงไปยัง วัตถุ smudge ดั้งเดิม ถูกส่งไปยังเมธอด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ไม่เปลี่ยนแปลง ท้ายที่สุดรอยเปื้อนเป็นตัวแปรอ้างอิงที่ยังคงชี้ไปที่วัตถุดั้งเดิมดั้งเดิมที่มีอายุ 5 ปี และเราไม่ได้ทำอะไรกับวัตถุนั้นเลย การเปลี่ยนแปลงอายุทั้งหมดของเราดำเนินการกับวัตถุใหม่ ดังนั้น ปรากฎว่าวัตถุถูกส่งไปยังเมธอดโดยการอ้างอิง สำเนาของวัตถุจะไม่ถูกสร้างขึ้นโดยอัตโนมัติ หากคุณส่งวัตถุ cat ไปยังเมธอดและเปลี่ยนอายุ คุณจะเปลี่ยนอายุของมัน แต่ตัวแปรอ้างอิงจะถูกคัดลอกเมื่อกำหนดค่าและ/หรือเรียกใช้เมธอด! ทำซ้ำสิ่งที่เราพูดเกี่ยวกับการส่งผ่าน primitives: "เมื่อเราเรียก เมธอด changeInt()และส่งintตัวแปร x (=15)เมธอดไม่ได้รับ ตัวแปร xแต่เป็นสำเนาของมัน ดังนั้น การเปลี่ยนแปลงใด ๆ ที่ทำกับสำเนาจึงไม่ส่งผลกระทบต่อx ดั้งเดิมของเราจะจบลงด้วยการโต้เถียงกันมากกว่าหนึ่งครั้งเกี่ยวกับวิธีส่งผ่านข้อโต้แย้งใน Java (แม้แต่ในหมู่นักพัฒนาที่มีประสบการณ์) แต่ตอนนี้คุณรู้แล้วว่ามันทำงานอย่างไร ติดตามต่อไป! :) เพื่อเสริมสิ่งที่คุณได้เรียนรู้ เราขอแนะนำให้คุณดูบทเรียนวิดีโอจากหลักสูตร Java ของเรา
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION