תרגום מאמר שנכתב על ידי פיטר ורהאס מאפריל 2014. מהמתרגם: המונח " שיטת ברירת מחדל " הופיע זה עתה בג'אווה ואני לא בטוח אם יש עבורו תרגום מבוסס לרוסית. אני אשתמש במונח "שיטת ברירת מחדל", למרות שאני לא חושב שזה אידיאלי. אני מזמין אותך לדון בתרגום מוצלח יותר.
מהי שיטת ברירת המחדל
כעת, עם שחרורו של Java 8, תוכלו להוסיף שיטות חדשות לממשקים כך שהממשק יישאר תואם למחלקות המיישמות אותו. זה מאוד חשוב אם אתה מפתח ספרייה המשמשת מתכנתים רבים מקייב ועד ניו יורק. לפני Java 8, אם הגדרת ממשק בספריה, לא תוכל להוסיף לו שיטות מבלי להסתכן שאפליקציה כלשהי שמריצה את הממשק שלך תישבר כאשר הוא יעודכן. אז ב-Java 8 אתה כבר לא יכול לפחד מזה? לא אתה לא יכול. הוספת שיטת ברירת מחדל לממשק עלולה להפוך מחלקות מסוימות ללא שמישות. בואו נסתכל תחילה על הדברים הטובים בשיטות ברירת המחדל. ב-Java 8 ניתן ליישם את השיטה ישירות בממשק. (עכשיו אפשר ליישם גם שיטות סטטיות בממשק, אבל זה כבר סיפור אחר.) שיטה המיושמת בממשק נקראת שיטת ברירת מחדל, והיא מסומנת על ידי מילת המפתח ברירת המחדל . אם מחלקה מיישמת ממשק, היא יכולה, אך לא נדרשת, ליישם את השיטות המיושמות בממשק. המחלקה יורשת את יישום ברירת המחדל. זו הסיבה שאין צורך לשנות מחלקות בעת שינוי הממשק שהם מיישמים.ירושה מרובה?
הדברים מסתבכים יותר אם מחלקה מיישמת יותר מממשק אחד (נניח, שניים), והם מיישמים את אותה שיטת ברירת מחדל. איזו שיטה תירש המחלקה? התשובה היא אף אחת. במקרה זה, המחלקה חייבת ליישם את השיטה עצמה (בין אם ישירות או על ידי ירושה ממחלקה אחרת). המצב דומה אם רק לממשק אחד יש שיטת ברירת מחדל, ובשני אותה שיטה מופשטת. Java 8 מנסה להיות ממושמע ולהימנע ממצבים מעורפלים. אם מתודות מוצהרות ביותר מממשק אחד, אזי לא ירש המחלקה יישום ברירת מחדל - תקבל שגיאת קומפילציה. אמנם, ייתכן שלא תקבל שגיאת קומפילציה אם הכיתה שלך כבר מורכבת. Java 8 אינו חזק מספיק בהקשר זה. יש לכך סיבות, שאני לא רוצה להיכנס לדיון בהן (למשל: מהדורת ה-Java כבר שוחררה והזמן לדיונים עבר מזמן ובכלל, זה לא המקום עבורם).- נניח שיש לך שני ממשקים ומחלקה מיישמת את שניהם.
- אחד הממשקים מיישם את שיטת ברירת המחדל m().
- אתה מרכיב את כל הממשקים והכיתה.
- אתה משנה ממשק שאין לו מתודה m() על ידי הכרזה עליו כשיטה מופשטת.
- אתה מרכיב רק את הממשק שהשתנה.
- התחל את השיעור.
- שנה את הממשק עם שיטת m() abstract והוסף מימוש ברירת מחדל.
- הרכיב את הממשק שהשתנה.
- הפעל מחלקה: שגיאה.
קוד לדוגמה
כדי להדגים את האמור לעיל, יצרתי ספריית בדיקה למחלקה C.java ו-3 ספריות משנה עבור הממשקים בקבצים I1.java ו-I2.java. ספריית השורש של הבדיקה מכילה את קוד המקור של המחלקה C.java. ספריית הבסיס מכילה גרסה של הממשקים המתאימים לביצוע והידור: לממשק I1 יש שיטת ברירת מחדל m(); לממשק I2 אין עדיין שיטות. למחלקה יש שיטהmain
כדי שנוכל להפעיל אותה כדי לבדוק אותה. הוא בודק אם יש ארגומנטים של שורת פקודה, כך שנוכל להפעיל אותו בקלות עם או בלי לקרוא את ה- m()
.
~/github/test$ cat C.java
public class C implements I1, I2 {
public static void main(String[] args) {
C c = new C();
if( args.length == 0 ){
c.m();
}
}
}
~/github/test$ cat base/I1.java
public interface I1 {
default void m(){
System.out.println("hello interface 1");
}
}
~/github/test$ cat base/I2.java
public interface I2 {
}
אתה יכול לקמפל ולהריץ את המחלקה משורת הפקודה.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
הספרייה התואמת מכילה גרסה של ממשק I2 שמצהירה על שיטת m() אבסטרקטית, וגם, מסיבות טכניות, עותק לא שונה של I1.java.
~/github/test$ cat compatible/I2.java
public interface I2 {
void m();
}
לא ניתן להשתמש בערכה כזו כדי להרכיב מחלקה C:
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
^
1 error
הודעת השגיאה מאוד מדויקת. עם זאת, יש לנו C.class מקומפילציה קודמת, ואם נקמפל את הממשקים לתוך הספרייה התואמת, יהיו לנו שני ממשקים שעדיין יכולים לשמש להפעלת המחלקה:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
הספרייה השלישית - wrong
- מכילה את גרסה I2, שגם מכריזה על השיטה m()
:
~/github/test$ cat wrong/I2.java
public interface I2 {
default void m(){
System.out.println("hello interface 2");
}
}
אתה אפילו לא צריך לדאוג לגבי קומפילציה. למרות שהמתודה הוכרזה פעמיים, עדיין ניתן להשתמש במחלקה ולהפעיל אותה עד שהמתודה m() תיקרא. בשביל זה אנחנו צריכים את ארגומנט שורת הפקודה:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
at C.m(C.java)
at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$
GO TO FULL VERSION