JavaRush /Java blogi /Random-UZ /Usul imzosi

Usul imzosi

Guruhda nashr etilgan
Salom! Siz allaqachon sohalar va usullar bilan o'z sinflaringizni yaratishni o'zlashtirgansiz. Bugun biz usullar haqida batafsil gaplashamiz. Albatta, biz buni ma'ruzalarimizda bir necha bor qilganmiz, lekin biz asosan umumiy fikrlar haqida gaplashdik. Bugun biz "qismlarga bo'lingan" usullarni tom ma'noda tahlil qilamiz - biz ular nimadan iboratligini, ularni yaratishning qanday variantlari mavjudligini va bularning barchasini qanday boshqarish mumkinligini bilib olamiz :) Ketdik!Usul imzosi - 1

Usul imzosi

Usulni tavsiflovchi barcha kodlar usul deklaratsiyasi deb ataladi . Usul imzosi muayyan tartibda usul nomi va parametr turlarini o'z ichiga oladi. Reklamaning umumiy ko'rinishini quyidagicha ta'riflash mumkin:
модификатор доступа, тип возвращаемого значения, Name метода(список параметров) {
    // тело метода
}
Keling, sinfning bir nechta usullari deklaratsiyasiga misol keltiraylik Dog.
public class Dog {

   String name;

   public Dog(String name) {
       this.name = name;
   }

   public static void main(String[] args) {
       Dog max = new Dog("Max");
       max.woof();

   }

   public void woof() {
       System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
   }

   public void run(int meters) {
       System.out.println("Собака по имени " + name + " пробежала " + meters + " метров!");
   }

   public String getName() {
       return name;
   }
}

1. Kirish modifikatori

Kirish modifikatori har doim birinchi bo'lib ro'yxatga olinadi. Barcha sinf usullari Dogmodifikator tomonidan belgilanadi public. Ya'ni, biz ularni boshqa har qanday sinfdan chaqirishimiz mumkin:
public class Main {

   public static void main(String[] args) {

       Dog butch = new Dog("Бутч");
       butch.run(100);
   }

}
Ko'rib turganingizdek, sinf usullariga Dogsinfda osongina kirish mumkin Main. Bu modifikator tufayli mumkin public. Java-da boshqa modifikatorlar mavjud va ularning barchasi boshqa sinf ichidagi usuldan foydalanishga imkon bermaydi. Biz ular haqida boshqa ma'ruzalarda gaplashamiz. Asosiysi, modifikator nima uchun javobgarligini eslab qolish: boshqa sinflarda usulning mavjudligi/mavjudligi :)

2. Static kalit so'z

Usullardan biri Dog, ya'ni main()kalit so'z bilan ko'rsatilgan static. Agar u mavjud bo'lsa, u kirish modifikatoridan keyin ko'rsatilishi kerak. Oldingi ma'ruzalarda biz statik sinf o'zgaruvchilari haqida gapirganimizni eslaysizmi? Usullarga qo'llanganda, bu so'z taxminan bir xil ma'noga ega. Agar usul sifatida ko'rsatilgan bo'lsa static, bu ma'lum bir sinf ob'ektiga murojaat qilmasdan foydalanish mumkinligini anglatadi. main()Haqiqatan ham, sinfda statik usulni ishga tushirish uchun Dogsiz misol yaratishingiz shart emas Dog; u holda ishlaydi. Agar bu usul statik bo'lmasa, uni ishlatish uchun avval ob'ekt yaratishimiz kerak bo'ladi.

3. Qaytish qiymati.

Agar bizning usulimiz biror narsani qaytarishi kerak bo'lsa, unda biz qaytarish qiymatining turini ko'rsatamiz. Buni oluvchi misolida ko'rish mumkin getName():
public String getName() {
   return name;
}
U turdagi ob'ektni qaytaradi String. Agar usul hech narsa qaytarmasa, voidusulda bo'lgani kabi type o'rniga kalit so'z ko'rsatiladi woof():
public void woof() {
   System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}

Xuddi shu nomdagi usullar

Bizning dasturimiz usul qanday ishlashi uchun bir nechta variantni talab qiladigan holatlar mavjud. Nega biz o'z sun'iy intellektimizni yaratmaymiz? Amazonda Alexa bor, Yandeksda Elis bor, nega biz yomonroqmiz? :) Temir odam haqidagi filmda Toni Stark o'zining ajoyib sun'iy intellektini yaratdi - JARVIS Ajoyib qahramonga hurmat bajo keltiramiz va uning sharafiga AIni nomlaymiz :) The Biz Jarvisga o'rgatishimiz kerak bo'lgan birinchi narsa - xonaga kirgan odamlarga salom berish (agar bunday buyuk intellekt odobsiz bo'lib chiqsa, g'alati bo'lar edi).
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");
   }
}
Konsol chiqishi:

Добрый вечер, Тони Старк, How ваши дела?
Ajoyib! Jarvis kirgan odamni qanday kutib olishni biladi. Ko'pincha, albatta, bu uning egasi - Toni Stark bo'ladi. Ammo u yolg'iz kelmasligi mumkin! Va bizning usulimiz sayHi()kirish sifatida faqat bitta argumentni oladi. Va shunga ko'ra, u kelganlardan faqat biriga salom bera oladi, ikkinchisini esa mensimaydi. Juda muloyim emasmi, rozimisiz?:/ Bunday holda, masalani hal qilish uchun sinfda bir xil nomdagi, lekin parametrlari har xil bo'lgan 2 ta usulni yozishimiz mumkin:
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?");
   }

}
Bu usulni haddan tashqari yuklash deb ataladi . Haddan tashqari yuklash bizning dasturimizni yanada moslashuvchan bo'lishiga va turli xil ish variantlariga moslashishiga imkon beradi. Keling, qanday ishlashini tekshirib ko'ramiz:
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");
   }
}
Konsol chiqishi:

Добрый вечер, Тони Старк, How ваши дела? 
Добрый вечер, Тони Старк, Капитан Америка, How ваши дела?
Ajoyib, ikkala variant ham ishladi :) Biroq, biz muammoni hal qilmadik! Agar uchta mehmon bo'lsa-chi? Albatta, biz sayHi()uchta mehmonning ismlarini qabul qilish uchun usulni yana ortiqcha yuklashimiz mumkin. Ammo ulardan 4 yoki 5 tasi bo'lishi mumkin va hokazo. Jarvisni har qanday nomlar bilan ishlashga o'rgatishning yana bir usuli bormi, millionlab usullarni ortiqcha yuklamasdan sayHi()? :/ Albatta bor! Aks holda, Java dunyodagi eng mashhur dasturlash tili bo'larmidi? ;)
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");
       System.out.println();
       jarvis.sayHi("Tony Stark", "Captain America");
   }
}
Parametr sifatida o'tkazilgan yozuv ( String...names) metodga ma'lum miqdordagi qatorlar uzatilganligini ko'rsatishga imkon beradi. Biz qancha bo'lishi kerakligini oldindan belgilamaymiz, shuning uchun usulimizning ishlashi endi ancha moslashuvchan bo'ladi:
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");
   }
}
Konsol chiqishi:

Добрый вечер, Тони Старк, How ваши дела? 
Добрый вечер, Капитан Америка, How ваши дела? 
Добрый вечер, Черная Вдова, How ваши дела? 
Добрый вечер, Халк, How ваши дела?
Usul ichida biz barcha argumentlarni aylanib chiqamiz va konsolga nomlar bilan tayyor iboralarni chiqaramiz. Bu erda biz soddalashtirilgan halqadan foydalanamiz for-each(siz allaqachon duch kelgansiz). Bu juda yaxshi, chunki yozish String...namesaslida barcha o'tkazilgan parametrlar kompilyator tomonidan massivga kiritilishini anglatadi. Shuning uchun, namessiz o'zgaruvchi bilan massivdagi kabi ishlashingiz mumkin, shu jumladan u orqali aylanish. Bundan tashqari, u istalgan miqdordagi uzatilgan liniyalar uchun ishlaydi! Ikki, o'n, hatto ming - usul har qanday mehmonlar soni bilan ishonchli ishlaydi. Barcha mumkin bo'lgan variantlar uchun ortiqcha yuklarni bajarishdan ko'ra ancha qulayroq, rozi emasmisiz? :) Usulni ortiqcha yuklashga yana bir misol keltiraylik. Jarvisga usul qo'shamiz printInfoFromDatabase(). U ma'lumotlar bazasidan konsolga shaxs haqidagi ma'lumotlarni chop etadi. Agar ma'lumotlar bazasi odam superqahramon yoki superyovuz ekanligini ko'rsatsa, bu ma'lumot ham ekranda ko'rsatiladi:
public class Jarvis {

   public  void printInfoFromDatabase (String bio) {

       System.out.println(bio);
   }

   public void printInfoFromDatabase(String bio, boolean isEvil, String nickname) {

       System.out.println(bio);
       if (!isEvil) {
           System.out.println("Также известен How супергерой " + nickname);
       } else {
           System.out.println("Также известен How суперзлодей " + nickname);
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.printInfoFromDatabase("Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Washington");
       System.out.println();
       jarvis.printInfoFromDatabase("Макс Эйзенхарт. Рост 188см, вес 86 кг.", true, "Магнето");
   }
}
Xulosa:

Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Washington
Макс Эйзенхарт. Рост 188см, вес 86 кг 
Также известен How суперзлодей Магнето
Bizning usulimiz biz kiritgan ma'lumotlarga qarab shunday ishlaydi. Yana bir muhim nuqta:Bahslar tartibi muhim! Aytaylik, bizning usulimiz kirish sifatida satr va raqamni oladi:
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!
   }
}
Agar sayYourAge()sinf usuli Mankirish sifatida satr va raqamni qabul qilsa, u holda ular dasturda o'tkazilishi kerak bo'lgan tartibdir! Agar biz ularni boshqacha tartibda o'tkazsak, kompilyator xato qiladi va odam o'z yoshini ayta olmaydi. Aytgancha, oxirgi ma'ruzada biz yoritgan konstruktorlar ham usullardir! Ular, shuningdek, haddan tashqari yuklanishi mumkin (turli argumentlar to'plamiga ega bir nechta konstruktorlarni yaratish) va ular uchun argumentlarni o'tkazish tartibi ham muhim ahamiyatga ega. Haqiqiy usullar! :)

Xuddi shunday parametrlarga ega usullarni qanday chaqirish mumkin

Ma'lumki, Java-da null kabi so'z mavjud. U bilan ishlashda null ob'ekt ham, ma'lumotlar turi ham emasligini tushunish juda muhimdir. Tasavvur qiling-a, bizda odam sinfi va introduce()odamning ismi va yoshini e'lon qiladigan usul bor. Bunday holda, yoshni matn shaklida etkazish yoki raqam sifatida ifodalash mumkin.
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man sasha = new Man();
       sasha.introduce("Sasha", "двадцать один");

       Man masha = new Man();
       masha.introduce("Мария", 32);
   }
}
Biz haddan tashqari yuklanish bilan allaqachon tanishmiz, shuning uchun biz bilamizki, usul har ikki safar ham kutilganidek ishlaydi:

Меня зовут Саша, мой возраст - двадцать один 
Меня зовут Мария, мой возраст - 32 
Agar biz ikkinchi parametr sifatida satr yoki raqam emas, null ni o'tkazsak nima bo'ladi?
public static void main(String[] args) {

   Man victor = new Man();
   victor.introduce("Виктор", null);//Ambiguous method call!
}
Biz kompilyatsiya xatosini olamiz! "Ambiguous method call" xatosi "noaniq usul chaqiruvi" deb tarjima qilinadi. Nima uchun bu paydo bo'lishi mumkin va "noaniqlik" nima? Bu aslida oddiy. Gap shundaki, bizda usulning ikkita varianti mavjud: ikkinchi argument sifatida Stringva bilan . IntegerLekin ikkalasi Stringham Integernull bo'lishi mumkin! Ikkala tur uchun (ular mos yozuvlar turlari bo'lgani uchun) null standart qiymatdir. Shuning uchun bu vaziyatda kompilyator usulning qaysi versiyasini chaqirish kerakligini aniqlay olmaydi. Ushbu muammoni hal qilish juda oddiy. Gap shundaki, null aniq mos yozuvlar turiga aylantirilishi mumkin. Shuning uchun, usulni chaqirganda, siz qavslar ichida ikkinchi argument uchun kerak bo'lgan ma'lumotlar turini ko'rsatishingiz mumkin! Kompilyator sizning "maslahatingizni" tushunadi va kerakli usulni chaqiradi:
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Метод со строкой и числом!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", (String) null);
   }
}
Xulosa:

Метод с двумя строками! 
Меня зовут Виктор, мой возраст - null
Ammo agar raqamli parametr intmos yozuvlar turidagi ob'ekt emas, balki ibtidoiy bo'lsa Integer, bunday xatolik yuzaga kelmaydi.
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, int age) {
       System.out.println("Метод со строкой и числом!!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", null);
   }
}
Nima uchun taxmin qildingizmi? Agar siz taxmin qilgan bo'lsangiz, yaxshi bajarildi :) Chunki primitivlar null ga teng bo'lishi mumkin emas. Endi kompilyatorda usulni chaqirish uchun faqat bitta variant bor introduce()- ikki qatorli. Usulning ushbu versiyasi har safar chaqirilganda qayta ishlanadi.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION