CodeGym /مدونة جافا /Random-AR /إعلان الطريقة
John Squirrels
مستوى
San Francisco

إعلان الطريقة

نشرت في المجموعة
أهلاً! لقد عرفت بالفعل كيفية إنشاء الفصول الدراسية الخاصة بك باستخدام الحقول والأساليب. الآن سوف نتناول الأساليب.
إعلان الطريقة - 1
بالطبع، لقد فعلنا ذلك بالفعل أكثر من مرة في دروسنا، لكننا غطينا بشكل أساسي العموميات. اليوم، سنقوم بتشريح الأساليب، ودراسة مكوناتها، والطرق المختلفة لإنشائها، وكيفية إدارتها كلها. :) دعنا نذهب!

إعلان الطريقة

كل التعليمات البرمجية التي تحدد الطريقة تسمى إعلان الطريقة . يمكن وصف الشكل العام لإعلان الطريقة على النحو التالي:

access modifier, return type, method name (parameter list) {
    // method body
}
كأمثلة، قم بإلقاء نظرة على الإعلانات الخاصة بالطرق المختلفة للفئة 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("A dog named " + name + " says \"Woof, woof!\"");
   }

   public void run(int distanceInFeet) {
       System.out.println("A dog named " + name + " ran " + distanceInFeet + " feet!");
   }

   public String getName() {
       return name;
   }
}

1. معدّل الوصول

تتم دائمًا الإشارة إلى معدّل الوصول أولاً. Dogيتم تمييز كافة أساليب الفصل باستخدام المعدل العام . هذا يعني أنه يمكننا استدعائهم من أي فئة أخرى:

public class Main {

   public static void main(String[] args) {

       Dog butch = new Dog("Butch");
       butch.run(100);
   }

}
كما ترون، Dogيمكن الوصول إلى أساليب الفصل بسهولة في Mainالفصل. هذا ممكن بسبب المعدل العام . في جافا، هناك معدلات أخرى. لا تسمح جميعها باستخدام الأساليب في فئات أخرى. وسنتحدث عنهم في دروس أخرى. الشيء الرئيسي الذي يجب تذكره هو ما هو المسؤول عن التعديل: ما إذا كان يمكن الوصول إلى الطريقة في فئات أخرى :)

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

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

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

إذا كان من المفترض أن تقوم طريقتنا بإرجاع شيء ما، فإننا نحدد نوع القيمة المرجعة. وهذا واضح من مثال getter getName():

public String getName() {
   return name;
}
تقوم بإرجاع Stringكائن. إذا لم تُرجع إحدى الطرق أي شيء، فسيتم استخدام الكلمة الأساسية voidwoof() بدلاً من ذلك، كما في الطريقة:

public void woof() {
   System.out.println("A dog named " + name + " says \"Woof, woof!\"");
}

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

هناك مواقف نحتاج فيها إلى عدة طرق مختلفة لاستدعاء إحدى الطرق. لماذا لا ننشئ ذكاءً اصطناعيًا خاصًا بنا؟ أمازون لديها Alexa، و Apple لديها Siri، فلماذا لا يكون لدينا واحد؟ :) في فيلم الرجل الحديدي، ابتكر توني ستارك ذكاءه الاصطناعي المذهل، جارفيس. دعونا نشيد بهذه الشخصية الرائعة ونطلق اسم الذكاء الاصطناعي الخاص بنا على شرفه. :) أول شيء يتعين علينا القيام به هو تعليم جارفيس إلقاء التحية على الأشخاص الذين يدخلون الغرفة (سيكون من الغريب أن يتبين أن هذا الفكر المذهل غير مهذب).

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

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");
   }
}
إخراج وحدة التحكم: مساء الخير، توني ستارك. كيف حالك؟ مساء الخير، توني ستارك وكابتن أمريكا. كيف حالك؟ ممتاز، كلا الإصدارين يعملان. :) لكننا لم نحل المشكلة! ماذا لو كان هناك ثلاثة ضيوف؟ يمكننا بالطبع زيادة تحميل 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?");
       }
   }

   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?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
   }
}
إخراج وحدة التحكم: مساء الخير، توني ستارك. كيف حالك؟ مساء الخير يا كابتن أمريكا. كيف حالك؟ مساء الخير أيتها الأرملة السوداء. كيف حالك؟ مساء الخير يا هالك. كيف حالك؟ داخل الطريقة، نقوم بالتكرار على جميع الوسائط ونعرض العبارات المنسقة بالأسماء. هنا نستخدم for-eachحلقة مبسطة (التي رأيتها من قبل). إنه مثالي هنا، لأن الترميز ( String...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("Also known as the superhero " + nickname);
       } else {
           System.out.println("Also known as the supervillain " + nickname);
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.printInfoFromDatabase("Laura Palmer. Date of birth: July 22, 1972. Twin Peaks, Washington");
       System.out.println();
       jarvis.printInfoFromDatabase("Max Eisenhardt. Height: 15.6 ft. Weight: 189 lbs. ", true, "Magneto");
   }
}
الإخراج: لورا بالمر. تاريخ الميلاد: 22 يوليو 1972. توين بيكس، واشنطن ماكس أيزنهاردت. الارتفاع: 15.6 قدم الوزن: 189 رطلا. يُعرف أيضًا باسم الشرير الفائق Magneto ، لذا، يعتمد سلوك طريقتنا على البيانات التي نمررها إليها. إليك نقطة أخرى مهمة: ترتيب الحجج مهم! لنفترض أن طريقتنا تأخذ سلسلة ورقمًا:

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

كيفية استدعاء الأساليب ذات المعلمات المماثلة

كما تعلمون، nullهي الكلمة الأساسية في جافا. من المهم جدًا أن تفهم أن nullهذا ليس كائنًا ولا نوع بيانات . تخيل أن لدينا Personفئة وطريقة introduce()تعلن عن اسم الشخص وعمره. علاوة على ذلك، يمكن تمرير العمر كنص أو رقم.

public class Person {

   public void introduce(String name, String age) {
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public static void main(String[] args) {

       Person alex = new Person();
       alex.introduce ("Alex", "twenty-one");

       Person mary = new Person();
       mary.introduce("Mary", 32);
   }
}
نحن بالفعل على دراية بالتحميل الزائد، لذلك نعلم أن كلتا الطريقتين ستتصرفان كما ينبغي: اسمي Alex. عمري واحد وعشرون اسمي مريم. عمري 32 عامًا ، لكن ماذا سيحدث إذا مررنا nullكمعامل ثانٍ بدلاً من سلسلة أو رقم؟

public static void main(String[] args) {

   Person victor = new Person();
   victor.introduce("Victor", null);// Ambiguous method call!
}
سنحصل على خطأ في التجميع! ما الذي يسبب هذا وما هو بالضبط "الغموض"؟ في الواقع، كل شيء بسيط للغاية. المشكلة هي أن لدينا نسختين من الطريقة: إحداهما باستخدام Stringa كوسيطة ثانية، والأخرى باستخدام Integera كوسيطة ثانية. ولكن يمكن أن يكون Stringكلاهما ! نظرًا لأنهما أنواع مرجعية، فهي القيمة الافتراضية لكليهما. ولهذا السبب لا يستطيع المترجم في هذه الحالة معرفة إصدار الطريقة الذي يجب عليه الاتصال به. الحل لهذه المشكلة بسيط للغاية. يمكن تحويلها بشكل صريح إلى نوع مرجعي محدد. وبالتالي، عند استدعاء أسلوب ما، يمكنك الإشارة بين قوسين إلى نوع البيانات الذي تريده للوسيطة الثانية! سيفهم المترجم "تلميحك" وسيستدعي الطريقة الصحيحة: IntegernullnullNull

public class Person {

   public void introduce(String name, String age) {
       System.out.println("Method with two strings!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Method with a string and a number!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public static void main(String[] args) {

       Person victor = new Person();
       victor.introduce("Victor", (String) null);
   }
}
الإخراج: طريقة مع سلسلتين! اسمي فيكتور. عمري فارغ لاحظ أنه إذا كانت معلمة الرقم بدائية int، بدلاً من مثيل لنوع مرجع عدد صحيح، فلن يكون هناك مثل هذا الخطأ.

public class Person {

   public void introduce(String name, String age) {
       System.out.println("Method with two strings!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public void introduce(String name, int age) {
       System.out.println("Method with a string and a number!!");
       System.out.println("My name is " + name + ". My age is " + age);
   }

   public static void main(String[] args) {

       Person victor = new Person();
       victor.introduce("Victor", null);
   }
}
يمكنك تخمين لماذا؟ إذا خمنت السبب، أحسنت! :) لأن البدائيين لا يمكن أن يكونوا null. الآن لدى المترجم خيار واحد فقط، أي استدعاء introduce()الأسلوب بسلسلتين. هذا هو إصدار الطريقة التي سيتم تشغيلها في كل مرة يتم فيها استدعاء الطريقة.

المزيد من القراءة:

تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION