JavaRush /בלוג Java /Random-HE /חתימת שיטה

חתימת שיטה

פורסם בקבוצה
שלום! כבר שלטת ביצירת שיעורים משלך, עם שדות ושיטות. היום נדבר בפירוט על השיטות. אנחנו, כמובן, עשינו את זה יותר מפעם אחת בהרצאות שלנו, אבל דיברנו בעיקר על נקודות כלליות. היום ממש ננתח את השיטות "בחלקים" - נגלה ממה הן מורכבות, אילו אפשרויות ליצירתן קיימות וכיצד ניתן לנהל את כל זה :) בוא נלך!חתימת השיטה - 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. החזר ערך.

אם השיטה שלנו חייבת להחזיר משהו, אז אנו מציינים את סוג ערך ההחזרה. ניתן לראות זאת בדוגמה של גטר getName():
public String getName() {
   return name;
}
זה מחזיר אובייקט מסוג String. אם השיטה לא מחזירה כלום, מילת המפתח תצוין במקום הסוג void, כמו בשיטה woof():
public void woof() {
   System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}

שיטות עם אותו שם

ישנם מצבים שבהם התוכנית שלנו דורשת מספר אפשרויות לאופן הפעולה של שיטה. למה שלא ניצור את הבינה המלאכותית שלנו? לאמזון יש את אלקסה, ליאנדקס יש את אליס, אז למה אנחנו גרועים יותר? :) בסרט על איירון מן, טוני סטארק יצר את האינטליגנציה המלאכותית יוצאת הדופן שלו - JARVIS בואו נחווה כבוד לדמות הנפלאה ונקרא לכבודו ה-AI שלנו :) The דבר ראשון שעלינו ללמד את ג'רוויס - לברך אנשים שנכנסים לחדר (זה יהיה מוזר אם אינטלקט כה גדול יתברר כלא מנומס).
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 מהם. וכך הלאה עד אינסוף. האם יש דרך אחרת ללמד את ג'רוויס לעבוד עם כל מספר של שמות, בלי מיליון עומסי שיטות 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אתה יכול לעבוד עם משתנה כמו עם מערך, כולל לולאה דרכו. יתר על כן, זה יעבוד עבור כל מספר של קווים מועברים! שניים, עשר, אפילו אלף - השיטה תעבוד בצורה אמינה עם כל מספר של אורחים. הרבה יותר נוח מלעשות עומסים על כל האפשרויות האפשריות, אתה לא מסכים? :) בוא ניתן דוגמה נוספת לעומס יתר בשיטה. בואו נוסיף שיטה לג'רוויס 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לוקחת מחרוזת ומספר כקלט, אז זה הסדר שבו הם צריכים לעבור בתוכנית! אם נעביר אותם בסדר אחר, המהדר יזרוק שגיאה והאדם לא יוכל לומר את גילו. אגב, גם הקונסטרוקטורים שסיקרנו בהרצאה האחרונה הם שיטות! הם גם יכולים להיות עומסים יתר על המידה (יוצרים כמה בנאים עם סטים שונים של ארגומנטים) ועבורם גם סדר העברת הטיעונים חשוב מהותית. שיטות אמיתיות! :)

כיצד לקרוא לשיטות עם פרמטרים דומים

כפי שאתה יודע, ב-Java יש מילה כזו כמו 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);
   }
}
ניחשתם למה? אם ניחשתם נכון, כל הכבוד :) כי פרימיטיבים לא יכולים להיות שווה ל-null. כעת לקומפיילר יש רק אפשרות אחת לקריאה למתודה introduce()- עם שתי שורות. גרסה זו של השיטה היא שתעובד בכל פעם שהשיטה תיקרא.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION