JavaRush /مدونة جافا /Random-AR /توقيع الطريقة

توقيع الطريقة

نشرت في المجموعة
مرحبًا! لقد أتقنت بالفعل إنشاء فئاتك الخاصة، باستخدام الحقول والأساليب. اليوم سنتحدث بالتفصيل عن الأساليب. وبالطبع قمنا بذلك أكثر من مرة في محاضراتنا، لكننا تحدثنا بشكل أساسي عن نقاط عامة. اليوم سنقوم بتحليل الأساليب حرفيًا "في أجزاء" - سنكتشف مما تتكون منه، وما هي الخيارات المتاحة لإنشائها وكيف يمكن إدارة كل هذا :) هيا بنا!توقيع الطريقة - 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. هناك معدّلات أخرى في Java، ولن تسمح لك جميعها باستخدام طريقة داخل فئة أخرى. وسنتحدث عنهم في محاضرات أخرى. الشيء الرئيسي هو أن تتذكر ما هو المسؤول عن المعدل: توفر/عدم إمكانية الوصول إلى الطريقة في الفئات الأخرى :)

2. الكلمة الأساسية الثابتة

تتم الإشارة إلى إحدى الطرق Dogبواسطة main()الكلمة الأساسية static. إذا كان موجودًا، فيجب تحديده بعد معدّل الوصول. هل تتذكر في المحاضرات السابقة تحدثنا عن متغيرات الفئة الثابتة؟ عند تطبيقها على الأساليب، فإن هذه الكلمة لها نفس المعنى تقريبًا. إذا تم تحديد الطريقة كـ static، فهذا يعني أنه يمكن استخدامها دون الرجوع إلى كائن فئة معينة. وفي الواقع، لتشغيل طريقة ثابتة main()في الفصل، Dogلا تحتاج إلى إنشاء مثيل Dog، فهو يعمل بدونه. إذا لم تكن هذه الطريقة ثابتة، فلاستخدامها سنحتاج أولاً إلى إنشاء كائن.

3. القيمة المرتجعة.

إذا كان يجب أن تقوم طريقتنا بإرجاع شيء ما، فإننا نشير بعد ذلك إلى نوع القيمة المرجعة. يمكن ملاحظة ذلك في مثال getter getName():
public String getName() {
   return name;
}
تقوم بإرجاع كائن من النوع String. إذا لم تُرجع الطريقة أي شيء، يتم تحديد الكلمة الأساسية بدلاً من النوع void، كما في الطريقة woof():
public void woof() {
   System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}

طرق بنفس الاسم

هناك مواقف يتطلب فيها برنامجنا عدة خيارات لكيفية عمل الطريقة. لماذا لا نصنع ذكاءنا الاصطناعي بأنفسنا؟ أمازون لديها Alexa، وYandex لديها Alice، فلماذا نحن أسوأ؟ :) في الفيلم الذي يدور حول الرجل الحديدي، ابتكر توني ستارك ذكاءه الاصطناعي المتميز - 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()وسيطة واحدة فقط كمدخل. وبناء على ذلك، لن يكون قادرا على إلقاء التحية إلا على واحد من القادمين، وسوف يتجاهل الآخر. ليس مهذبًا جدًا، أوافق؟:/ في هذه الحالة، لحل المشكلة، يمكننا ببساطة كتابة طريقتين في الفصل بنفس الاسم، ولكن مع معلمات مختلفة:
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 منهم، وهكذا إلى ما لا نهاية. هل هناك طريقة أخرى لتعليم جارفيس العمل مع أي عدد من الأسماء، دون التحميل الزائد على مليون طريقة sayHi()؟ :/ بالطبع! وإلا هل ستكون Java لغة البرمجة الأكثر شعبية في العالم؟ ;)
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يمكنك العمل مع متغير كما هو الحال مع المصفوفة، بما في ذلك التكرار من خلاله. علاوة على ذلك، فإنه سيعمل مع أي عدد من الخطوط المنقولة! اثنان، عشرة، وحتى ألف - ستعمل الطريقة بشكل موثوق مع أي عدد من الضيوف. إنه أكثر ملاءمة من إجراء التحميل الزائد لجميع الخيارات الممكنة، ألا توافق على ذلك؟ :) دعنا نعطي مثالاً آخر عن التحميل الزائد للطريقة. دعونا نضيف طريقة إلى Jarvis 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 ليست كائنًا ولا نوع بيانات. تخيل أن لدينا رجل فئة وطريقة 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!
}
سنحصل على خطأ في التجميع! تتم ترجمة الخطأ "استدعاء أسلوب غامض" إلى "استدعاء أسلوب غامض". لماذا يمكن أن تنشأ وما هو "الغموض"؟ انها في الواقع بسيطة. الأمر هو أن لدينا نوعين مختلفين من الطريقة: with Stringوwith Integerكوسيطة ثانية. لكن كلاهما String، Integerويمكن أن يكونا فارغين! بالنسبة لكلا النوعين (بما أنهما أنواع مرجعية)، فإن القيمة 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);
   }
}
هل خمنت لماذا؟ إذا خمنت ذلك، أحسنت :) لأن البدائيات لا يمكن أن تكون مساوية للصفر. الآن لدى المترجم خيار واحد فقط لاستدعاء الطريقة introduce()- بخطين. هذا هو الإصدار من الطريقة التي ستتم معالجتها في كل مرة يتم فيها استدعاء الطريقة.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION