JavaRush /وبلاگ جاوا /Random-FA /امضای روش

امضای روش

در گروه منتشر شد
سلام! شما قبلاً در ایجاد کلاس های خود با فیلدها و روش ها تسلط پیدا کرده اید. امروز به طور مفصل در مورد روش ها صحبت خواهیم کرد. ما البته این کار را بیش از یک بار در سخنرانی هایمان انجام داده ایم، اما عمدتاً در مورد نکات کلی صحبت کرده ایم. امروز ما به معنای واقعی کلمه روش ها را "در بخش" تجزیه و تحلیل خواهیم کرد - خواهیم فهمید که از چه چیزی تشکیل شده است ، چه گزینه هایی برای ایجاد آنها وجود دارد و چگونه می توان همه اینها را مدیریت کرد :) بیایید برویم!امضای روش - 1

امضای روش

تمام کدهایی که یک متد را توصیف می کنند، اعلان متد نامیده می شوند . امضای متد شامل نام متد و انواع پارامترها به ترتیب خاصی است. ظاهر کلی آگهی را می توان به شرح زیر توصیف کرد:
модификатор доступа, тип возвращаемого значения, Name метода(список параметров) {
    // тело метода
}
بیایید مثالی از اعلان چندین متد کلاس را در نظر بگیریم 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. اصلاح کننده دسترسی

اصلاح کننده دسترسی همیشه اول لیست می شود. تمام متدهای کلاس Dogتوسط اصلاح کننده تعیین می شوند public. یعنی می توانیم آنها را از هر کلاس دیگری فراخوانی کنیم:
public class Main {

   public static void main(String[] args) {

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

}
متدهای کلاس Dog، همانطور که می بینید، به راحتی در کلاس قابل دسترسی هستند Main. این به لطف اصلاح کننده امکان پذیر است public. اصلاح‌کننده‌های دیگری در جاوا وجود دارد و همه آنها به شما اجازه نمی‌دهند از یک متد در کلاس دیگر استفاده کنید. در سخنرانی های دیگر در مورد آنها صحبت خواهیم کرد. نکته اصلی این است که به یاد داشته باشید که اصلاح کننده چه مسئولیتی دارد: در دسترس بودن / عدم دسترسی به روش در کلاس های دیگر :)

2. کلمه کلیدی ثابت

یکی از روش ها Dog، یعنی main()با کلمه کلیدی نشان داده می شود static. اگر وجود دارد، پس از اصلاح کننده دسترسی باید مشخص شود. به یاد دارید در سخنرانی های قبلی در مورد متغیرهای کلاس ایستا صحبت کردیم؟ هنگامی که به روش ها اطلاق می شود، این کلمه تقریباً همان معنی را دارد. اگر یک متد به صورت مشخص شده باشد static، به این معنی است که می توان آن را بدون ارجاع به یک شی کلاس خاص استفاده کرد. و در واقع، برای اجرای یک متد استاتیک main()در یک کلاس، Dogنیازی به ایجاد یک نمونه ندارید Dog؛ بدون آن اجرا می شود. اگر این روش ثابت نبود، برای استفاده از آن ابتدا باید یک شی ایجاد کنیم.

3. ارزش بازگشتی.

اگر متد ما باید چیزی را برگرداند، سپس نوع مقدار بازگشتی را نشان می‌دهیم. این را می توان در مثال یک گیرنده مشاهده کرد getName():
public String getName() {
   return name;
}
یک شی از نوع را برمی گرداند String. اگر متد چیزی برگرداند، به جای نوع void، کلمه کلیدی مانند متد مشخص می شود woof():
public void woof() {
   System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}

روش هایی با همین نام

شرایطی وجود دارد که برنامه ما به چندین گزینه برای نحوه عملکرد یک متد نیاز دارد. چرا ما هوش مصنوعی خود را ایجاد نمی کنیم؟ آمازون الکسا دارد، یاندکس آلیس دارد، پس چرا ما بدتر هستیم؟ :) در فیلم درباره مرد آهنی، تونی استارک هوش مصنوعی برجسته خود را خلق کرد - 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()فقط یک آرگومان را به عنوان ورودی می گیرد. و بر این اساس، او فقط می تواند به یکی از کسانی که می آیند سلام کند و دیگری را نادیده می گیرد. خیلی مودبانه نیستید، موافقید؟:/ در این صورت برای حل مشکل، می توانیم به سادگی 2 متد را در کلاس با همان نام، اما با پارامترهای مختلف بنویسیم:
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 مورد از آنها وجود داشته باشد و به همین ترتیب ad infinitum. آیا راه دیگری برای آموزش جارویس وجود دارد که با هر تعداد نام کار کند، بدون میلیون ها بار اضافه بار sayHi()؟ :/ البته دارم! در غیر این صورت آیا جاوا محبوب ترین زبان برنامه نویسی در جهان خواهد بود؟ ;)
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");
   }
}
رکورد ( 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 ваши дела?
در داخل متد، همه آرگومان ها را حلقه حلقه می کنیم و عبارات آماده با نام را به کنسول خروجی می دهیم. در اینجا ما از یک حلقه ساده شده استفاده می کنیم for-each(شما قبلاً با آن مواجه شده اید). این عالی است زیرا نوشتن String...namesدر واقع به این معنی است که تمام پارامترهای ارسال شده توسط کامپایلر در یک آرایه قرار می گیرند. بنابراین، namesمی توانید با یک متغیر مانند یک آرایه کار کنید، از جمله حلقه زدن از طریق آن. علاوه بر این، برای هر تعداد از خطوط انتقال یافته کار خواهد کرد! دو، ده، حتی هزار - این روش با هر تعداد مهمان به طور قابل اعتماد کار خواهد کرد. خیلی راحت تر از انجام اضافه بار برای همه گزینه های ممکن، موافق نیستید؟ :) بیایید مثال دیگری از بارگذاری بیش از حد روش ارائه دهیم. بیایید یک روش به جارویس اضافه کنیم printInfoFromDatabase(). اطلاعات مربوط به شخص را از پایگاه داده به کنسول چاپ می کند. اگر پایگاه داده نشان دهد که شخصی یک ابرقهرمان یا ابرشرور است، این اطلاعات نیز روی صفحه نمایش داده می شود:
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, "Магнето");
   }
}
نتیجه:

Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Washington
Макс Эйзенхарт. Рост 188см, вес 86 кг 
Также известен 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یک رشته و یک عدد را به عنوان ورودی بگیرد، این ترتیبی است که باید در برنامه ارسال شوند! اگر آنها را به ترتیب دیگری پاس کنیم، کامپایلر خطا می دهد و فرد نمی تواند سن خود را بگوید. ضمناً سازنده هایی که در سخنرانی گذشته به آنها پرداختیم نیز روش هستند! آنها همچنین می توانند بیش از حد بارگذاری شوند (چند سازنده با مجموعه های مختلف آرگومان ایجاد کنید) و برای آنها ترتیب ارسال آرگومان ها نیز اساساً مهم است. روش های واقعی! :)

نحوه فراخوانی متدها با پارامترهای مشابه

همانطور که می دانید در جاوا کلمه ای به نام null وجود دارد. هنگام کار با آن، درک این نکته بسیار مهم است که null نه یک شی است و نه یک نوع داده. تصور کنید ما یک کلاس Man و متدی داریم introduce()که نام و سن یک فرد را اعلام می کند. در این صورت می توان سن را به صورت متن منتقل کرد یا به صورت عدد بیان کرد.
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);
   }
}
ما قبلاً با بارگذاری بیش از حد آشنا هستیم، بنابراین می دانیم که این روش هر دو بار همانطور که انتظار می رود کار خواهد کرد:

Меня зовут Саша, мой возраст - двадцать один 
Меня зовут Мария, мой возраст - 32 
اما اگر null را به عنوان پارامتر دوم ارسال کنیم، نه رشته یا عدد، چه اتفاقی می‌افتد؟
public static void main(String[] args) {

   Man victor = new Man();
   victor.introduce("Виктор", null);//Ambiguous method call!
}
یک خطای کامپایل دریافت خواهیم کرد! خطای " فراخوانی روش مبهم " به عنوان " فراخوانی روش مبهم " ترجمه می شود. چرا ممکن است ایجاد شود و "ابهام" چیست؟ در واقع ساده است. مسئله این است که ما دو نوع از روش داریم: با Stringو با Integerبه عنوان آرگومان دوم. اما هر دو String، و Integerمی تواند پوچ باشد! برای هر دو نوع (از آنجایی که آنها انواع مرجع هستند)، null مقدار پیش فرض است. به همین دلیل است که کامپایلر در این شرایط نمی تواند بفهمد که کدام نسخه از متد را باید فراخوانی کند. حل این مشکل بسیار ساده است. نکته این است که null را می توان به طور صریح به یک نوع مرجع خاص تبدیل کرد. بنابراین، هنگام فراخوانی یک متد، می توانید در داخل پرانتز نوع داده مورد نیاز برای آرگومان دوم را مشخص کنید! کامپایلر "اشاره" شما را درک می کند و متد مورد نیاز را فراخوانی می کند:
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);
   }
}
نتیجه:

Метод с двумя строками! 
Меня зовут Виктор, мой возраст - null
اما اگر پارامتر عددی یک شی اولیه intو نه یک شی از نوع مرجع باشد Integer، چنین خطایی رخ نمی‌دهد.
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);
   }
}
حدس زدی چرا؟ اگر حدس زدید، آفرین :) چون primitive ها نمی توانند برابر با null باشند. اکنون کامپایلر تنها یک گزینه برای فراخوانی متد دارد introduce()- با دو خط. این نسخه از متد است که هر بار که متد فراخوانی می شود پردازش می شود.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION