JavaRush /Blog Java /Random-MS /Kaedah, parameter mereka, interaksi dan lebihan beban

Kaedah, parameter mereka, interaksi dan lebihan beban

Diterbitkan dalam kumpulan
Hello lagi! Dalam kuliah terakhir, kami berkenalan dengan kelas dan pembina, dan belajar cara mencipta kelas kami sendiri. Kaedah, parameternya, interaksi dan lebihan beban - 1Hari ini kita akan melihat dengan lebih dekat bahagian penting dalam kelas sebagai kaedah. Kaedah ialah satu set arahan yang membolehkan anda melakukan beberapa operasi dalam atur cara. Dengan kata lain, kaedah adalah fungsi; sesuatu yang kelas anda boleh lakukan. Dalam bahasa pengaturcaraan lain, kaedah sering dipanggil "fungsi," tetapi dalam Java perkataan "kaedah" telah menjadi lebih popular :) Dalam kuliah terakhir, jika anda masih ingat, kami mencipta kaedah mudah untuk kelas Kucing supaya kucing kami boleh mengeong. dan lompat:
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()dan jump()merupakan kaedah kelas kami. Hasil kerja mereka adalah output ke konsol:
Мяу!
Прыг-скок!
Kaedah kami agak mudah: mereka hanya mencetak teks ke konsol. Tetapi di Jawa, kaedah mempunyai tugas utama - mereka mesti melakukan tindakan pada data objek . Tukar nilai data objek, ubahnya, keluarkannya ke konsol atau lakukan perkara lain dengannya. Kaedah semasa kami tidak melakukan apa-apa dengan data objek Cat. Mari lihat contoh yang lebih jelas:
public class Truck {

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

    public int getVolume() {
        int volume = length * width * height;
        return volume;
    }
}
Sebagai contoh, kami mempunyai kelas yang mewakili trak - Truck. Treler trak mempunyai panjang, lebar dan tinggi serta berat (ini akan diperlukan kemudian). Dalam kaedah, getVolume()kami melakukan pengiraan - kami mengubah data objek kami kepada nombor yang menunjukkan jumlah (kami mendarabkan panjang, lebar dan ketinggian). Ini adalah nombor yang akan menjadi hasil kaedah. Sila ambil perhatian - dalam penerangan kaedah ia ditulis public int getVolume. Ini bermakna hasil kaedah ini mestilah nombor dalam bentuk int. Kami telah mengira hasil kaedah, dan sekarang kami mesti mengembalikannya ke program kami yang dipanggil kaedah. Untuk mengembalikan hasil kaedah dalam Java, kata kunci digunakan return.
return volume;

Parameter kaedah

Kaedah boleh menerima nilai sebagai input, yang dipanggil "parameter kaedah". Kaedah semasa kami getVolume()dalam kelas Trucktidak menerima sebarang parameter, jadi mari kita cuba mengembangkan contoh dengan trak. Jom buat kelas baru - BridgeOfficer. Seorang pegawai polis sedang bertugas di atas jambatan dan memeriksa semua trak yang lalu untuk memastikan muatannya tidak melebihi had berat yang dibenarkan.
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;
        }
    }
}
Kaedah ini checkTruckmengambil satu parameter sebagai input - objek trak Truckdan menentukan sama ada pegawai akan membenarkan trak itu ke jambatan atau tidak. Logik di dalam kaedah ini agak mudah: jika berat trak melebihi maksimum yang dibenarkan, kaedah itu kembali false. Anda perlu mencari jalan lain :( Jika berat kurang daripada atau sama dengan maksimum, anda boleh lulus, dan kaedah itu kembali true. Jika anda masih tidak memahami sepenuhnya frasa “kembali”, “kaedah mengembalikan nilai ” - mari berehat daripada pengaturcaraan dan lihat ini menggunakan contoh mudah daripada kehidupan dunia sebenar :) Katakan anda jatuh sakit dan tidak bekerja selama beberapa hari. Anda datang ke jabatan perakaunan dengan cuti sakit anda, yang mesti anda bayar. Jika kita membuat analogi dengan kaedah, maka akauntan mempunyai kaedah paySickLeave()("gaji cuti sakit"). Anda lulus sijil cuti sakit kepada kaedah ini sebagai parameter (tanpanya, kaedah itu tidak akan berfungsi dan anda tidak akan dibayar apa-apa!). Di dalam kaedah lembaran kerja, pengiraan yang diperlukan dibuat (akaun menggunakannya untuk mengira berapa banyak yang perlu dibayar oleh syarikat kepada anda), dan hasil kerja itu dikembalikan kepada anda - sejumlah wang. Program ini berfungsi dengan cara yang sama. Ia memanggil kaedah, menghantar data ke sana, dan akhirnya menerima hasilnya. Berikut adalah kaedah main()untuk program kami 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);
}
Kami sedang mencipta dua trak dengan muatan 10,000 dan 20,000. Pada masa yang sama, berat maksimum untuk jambatan di mana pegawai bertugas ialah 15,000. Program yang dipanggil kaedah officer.checkTruck(first), kaedah mengira segala-galanya dan mengembalikan hasilnya kepada program - true, dan atur cara menyimpannya dalam pembolehubah boolean canFirstTruckGo. Sekarang dia boleh melakukan apa sahaja yang dia mahu dengannya (sama seperti anda dengan wang yang anda terima daripada akauntan). Akhirnya kod
boolean canFirstTruckGo = officer.checkTruck(first);
turun ke
boolean canFirstTruckGo = true;
Perkara yang sangat penting: pengendali returnbukan sahaja mengembalikan hasil kaedah, tetapi juga menamatkan kerjanya ! Semua kod yang ditulis selepas pemulangan tidak akan dilaksanakan!
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!");
    }
}
Frasa yang pegawai katakan tidak akan dikeluarkan kepada konsol, kerana kaedah itu telah mengembalikan hasil dan menyelesaikan kerjanya! Program ini kembali ke titik di mana kaedah dipanggil. Anda tidak perlu risau tentang perkara ini sendiri - pengkompil Java cukup bijak untuk membuang ralat jika anda cuba menulis kod selepas return.

Avengers: Perang Pilihan

Terdapat situasi apabila program kami memerlukan beberapa pilihan untuk cara kaedah berfungsi. Mengapa kita tidak mencipta kecerdasan buatan kita sendiri? Amazon ada Alexa, Yandex ada Alice, jadi kenapa kita lebih teruk? :) Dalam filem tentang Iron Man, Tony Stark mencipta kecerdasan buatannya yang luar biasa - JARVIS Mari kita beri penghormatan kepada watak yang hebat dan namakan AI kita sebagai penghormatan kepadanya :) perkara pertama yang mesti kita ajar Jarvis - menyapa orang yang masuk ke dalam bilik (alangkah peliknya jika akal sehebat itu ternyata tidak sopan).
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");
    }
}
Output konsol:
Добрый вечер, Тони Старк, How ваши дела?
Hebat! Jarvis tahu bagaimana menyapa seseorang yang masuk. Selalunya, sudah tentu, ia akan menjadi pemiliknya - Tony Stark. Tetapi dia mungkin tidak datang sendirian! Dan kaedah kami sayHi()hanya mengambil satu hujah sebagai input. Dan, sewajarnya, dia akan dapat menyambut hanya salah seorang daripada mereka yang datang, dan akan mengabaikan yang lain. Tidak begitu sopan, setuju? :/ Dalam kes ini, untuk menyelesaikan masalah, kita hanya boleh menulis 2 kaedah dalam kelas dengan nama yang sama, tetapi dengan parameter yang berbeza:
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?");
    }
}
Ini dipanggil kaedah overloading . Lebihan beban membolehkan program kami menjadi lebih fleksibel dan menampung pilihan kerja yang berbeza. Mari semak cara ia berfungsi:
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");
    }
}
Output konsol:
Добрый вечер, Тони Старк, How ваши дела?
Добрый вечер, Тони Старк, Капитан Америка, How ваши дела?
Hebat, kedua-dua pilihan berjaya :) Walau bagaimanapun, kami tidak menyelesaikan masalah! Bagaimana jika ada tiga tetamu? Sudah tentu, kita boleh membebankan kaedah sekali lagi sayHi()untuk menerima nama tiga tetamu. Tetapi boleh ada 4 atau 5 daripadanya. Dan seterusnya ad infinitum. Adakah terdapat cara lain untuk mengajar Jarvis bekerja dengan beberapa nama, tanpa satu juta kaedah berlebihan sayHi()? :/ Sudah tentu ada! Jika tidak, adakah Java akan menjadi bahasa pengaturcaraan paling popular di dunia? ;)
public void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ", How are you doing?");
    }
}
Rekod ( String...names) diluluskan sebagai parameter membolehkan kami menunjukkan bahawa bilangan rentetan tertentu dihantar ke kaedah. Kami tidak menyatakan terlebih dahulu jumlah yang sepatutnya, jadi pengendalian kaedah kami kini menjadi lebih fleksibel:
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");
    }
}
Output konsol:
Добрый вечер, Тони Старк, How ваши дела?
Добрый вечер, Капитан Америка, How ваши дела?
Добрый вечер, Черная Вдова, How ваши дела?
Добрый вечер, Халк, How ваши дела?
Beberapa kod di sini adalah asing kepada anda, tetapi jangan kisah itu. Intipatinya adalah mudah - kaedahnya melalui semua nama secara bergilir-gilir dan menyambut setiap tetamu! Selain itu, ia akan berfungsi untuk sebarang bilangan talian yang dipindahkan! Dua, sepuluh, malah seribu - kaedah ini akan berfungsi dengan pasti dengan mana-mana bilangan tetamu. Jauh lebih mudah daripada melakukan lebihan untuk semua pilihan yang mungkin, adakah anda bersetuju? :) Satu lagi perkara penting: susunan hujah itu penting! Katakan kaedah kami mengambil rentetan dan nombor sebagai input:
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!
    }
}
Jika kaedah sayYourAgekelas Manmengambil rentetan dan nombor sebagai input, maka ini ialah tertib di mana ia perlu diluluskan dalam program! Jika kita lulus mereka dalam susunan yang berbeza, pengkompil akan membuang ralat dan orang itu tidak akan dapat memberitahu umurnya. Ngomong-ngomong, pembina yang kami bincangkan dalam kuliah lepas juga merupakan kaedah! Mereka juga boleh dibebankan (buat beberapa pembina dengan set hujah yang berbeza) dan bagi mereka susunan menghantar hujah juga pada asasnya penting. Kaedah sebenar! :)

Dan sekali lagi mengenai parameter

Ya, ya, kita belum selesai dengan mereka lagi :) Topik yang akan kita pertimbangkan sekarang adalah sangat penting. Terdapat peluang 90% bahawa mereka akan bertanya tentang perkara ini pada semua temuduga masa depan anda! Kami akan bercakap tentang menghantar parameter kepada kaedah. Mari lihat contoh mudah:
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);
    }
}
Mesin masa mempunyai dua kaedah. Kedua-duanya mengambil sebagai input nombor yang mewakili tahun semasa dan sama ada kenaikan atau pengurangan nilai (bergantung pada sama ada kita mahu kembali ke masa atau ke masa hadapan). Tetapi, seperti yang dapat dilihat dari output konsol, kaedah itu tidak berfungsi! Output konsol:
Какой сейчас год?
2020
А сейчас?
2020
Kami lulus pembolehubah currentYearkepada kaedah goToPast(), tetapi nilainya tidak berubah. Seperti pada tahun 2020, ia kekal begitu. Tapi kenapa? :/ Kerana primitif dalam Java dihantar kepada kaedah mengikut nilai. Apakah maksudnya? Apabila kita memanggil kaedah goToPast()dan menghantar pembolehubah kita di sana int currentYear = 2020, bukan pembolehubah itu sendiri yang masuk ke dalam kaedah itu currentYear, tetapi salinannya . Nilai salinan ini, sudah tentu, juga bersamaan dengan 2020, tetapi semua perubahan yang berlaku pada salinan tidak sama sekali mempengaruhi pembolehubah asal kamicurrentYear ! Mari jadikan kod kami lebih bertele-tele dan lihat apa yang berlaku dengan 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);
    }
}
Output konsol:
Какой год в самом начале работы программы?
2020
Метод goToPast начал работу!
Значение currentYear внутри метода goToPast (в начале) = 2020
Значение currentYear внутри метода goToPast (в конце) = 2010
А сейчас Howой год?
2020
Ini jelas menunjukkan bahawa pembolehubah yang dihantar kepada kaedah tersebut goToPast()hanyalah salinan currentYear. Dan menukar salinan tidak mempunyai kesan ke atas makna "asal". " Melewati rujukan " mempunyai makna yang bertentangan. Jom amalkan kucing! Maksud saya, mari kita lihat seperti apa pautan melalui menggunakan kucing sebagai contoh :)
public class Cat {

    int age;

    public Cat(int age) {
        this.age = age;
    }
}
Kini, dengan bantuan mesin masa kami, kami akan melancarkan Barsik, pengembara masa kucing pertama di dunia, ke masa lalu dan masa depan! Mari tukar kelas TimeMachinesupaya mesin boleh berfungsi dengan objek Cat;
public class TimeMachine {

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

    public void goToPast(Cat cat) {
        cat.age -= 10;
    }
}
Kaedah kini mengubah bukan sahaja nombor yang diluluskan, tetapi medan ageobjek tertentu Cat. Dalam kes primitif, seperti yang anda ingat, kami tidak berjaya: nombor asal tidak berubah. Mari lihat apa yang berlaku di sini!
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);
}
Output konsol:
Сколько лет Барсику в самом начале работы программы?
5
А теперь?
15
Елки-палки! Барсик постарел на 10 лет! Живо гони назад!
Получилось? Мы вернули коту его изначальный возраст?
5
Wah! Sekarang kaedah itu berfungsi dengan berbeza: kucing kami tiba-tiba tua, dan kemudian kelihatan lebih muda lagi! :) Mari cuba fikirkan sebabnya. Tidak seperti contoh dengan primitif, dalam kes objek rujukan kepada objek diserahkan kepada kaedah. Rujukan kepada objek asal kami telah dihantar goToFuture(barsik)kepada kaedah . Oleh itu, apabila kita menukar kaedah di dalam , kita mengakses kawasan ingatan di mana objek kita disimpan. Ini adalah pautan ke Barsik yang sama yang kami buat pada awalnya. Ini dipanggil "laluan dengan rujukan"! Walau bagaimanapun, dengan pautan ini semuanya tidak begitu mudah :) Mari cuba ubah contoh kami: 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);
    }
}
Output konsol:
Сколько лет Барсику в самом начале работы программы?
5
Барсик отправился в будущее! Его возраст изменился?
5
А если попробовать в прошлое?
5
Tidak berfungsi lagi! O_O Mari kita fikirkan apa yang berlaku :) Ini semua tentang kaedah goToPast/ goToFuturedan mekanik cara pautan berfungsi. Sekarang perhatian!Perkara ini adalah yang paling penting dalam memahami cara pautan dan kaedah berfungsi. Malah, apabila kita memanggil kaedah, goToFuture(Cat cat)bukan rujukan objek itu sendiri yang dihantar kepadanya cat, tetapi salinan rujukan ini. Iaitu, apabila kita menghantar objek kepada kaedah, terdapat dua rujukan kepada objek ini . Ini sangat penting untuk memahami apa yang berlaku. Lagipun, inilah sebabnya contoh terakhir kami tidak mengubah umur kucing. Dalam contoh sebelumnya dengan menukar umur, kami hanya mengambil rujukan yang diluluskan di dalam kaedah goToFuture(), menemui objek dalam ingatan menggunakannya dan menukar umurnya ( cat.age += 10). Sekarang di dalam kaedah goToFuture()kita mencipta objek baru
(cat = new Cat(cat.age)),
dan pautan salinan yang sama yang dihantar kepada kaedah diberikan objek ini. Akibatnya:
  • Pautan pertama ( Cat barsik = new Cat(5)) menunjuk kepada kucing asal (dengan umur 5)
  • Selepas kami menyerahkan pembolehubah catkepada kaedah goToPast(Cat cat)dan memberikannya kepada objek baharu, rujukan telah disalin.
Selepas ini, kita mempunyai situasi terakhir: dua pautan menghala ke dua objek berbeza. Tetapi kami menukar umur hanya satu daripada mereka - yang kami cipta dalam kaedah.
cat.age += 10;
Dan secara semula jadi, apabila kita mengeluarkannya main()ke konsol dalam kaedah barsik.age, kita melihat bahawa umurnya tidak berubah. Lagipun barsik, ini ialah pembolehubah rujukan yang masih menunjuk kepada objek asal yang lama dengan umur 5 tahun, yang tiada apa-apa berlaku. Semua manipulasi kami dengan usia dilakukan pada objek baru. Oleh itu, ternyata objek dihantar ke kaedah melalui rujukan. Salinan objek tidak pernah dibuat secara automatik. Jika anda menghantar objek kucing kepada kaedah dan menukar umurnya, ia akan berjaya berubah. Tetapi nilai pembolehubah rujukan disalin apabila menetapkan dan/atau kaedah memanggil! Mari kita ulang di sini perenggan tentang lulus primitif: "Apabila kita memanggil kaedah changeInt()dan menghantar pembolehubah kita ke sana int x = 15, bukan pembolehubah itu sendiri yang masuk ke dalam kaedah itu x, tetapi salinannya . Lagipun, semua perubahan yang berlaku pada salinan itu tidak mempengaruhi pembolehubah asal kami dalam apa jua cara x.” Dengan menyalin pautan, semuanya berfungsi sama! Anda lulus objek kucing kepada kaedah. Jika anda melakukan sesuatu dengan kucing itu sendiri (iaitu, dengan objek dalam ingatan), semua perubahan akan berjaya dilalui - kami hanya mempunyai satu objek dan masih memilikinya. Tetapi jika di dalam kaedah anda mencipta objek baharu dan menyimpannya dalam pembolehubah rujukan, yang merupakan parameter kaedah, mulai sekarang kita mempunyai dua objek dan dua pembolehubah rujukan. Itu sahaja! Ia tidak semudah itu, malah anda mungkin perlu bersyarah beberapa kali. Tetapi perkara utama ialah anda telah mempelajari topik yang sangat penting ini. Anda akan sering menghadapi pertikaian (walaupun dalam kalangan pembangun berpengalaman) tentang cara hujah diluluskan dalam Java. Sekarang anda tahu dengan tepat cara ia berfungsi. Teruskan! :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION