JavaRush /בלוג Java /Random-HE /כיתות פנימיות מקוננות או כיתות פנימיות בג'אווה

כיתות פנימיות מקוננות או כיתות פנימיות בג'אווה

פורסם בקבוצה
שלום! היום נתחיל להסתכל על נושא חשוב - איך עובדות מחלקות מקוננות בג'אווה. באנגלית הם נקראים Nested classes. Java מאפשרת לך ליצור כמה מחלקות בתוך אחרים:
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
מחלקות אלו נקראות מקוננות. הם מחולקים ל-2 סוגים:
  1. מחלקות מקוננות לא סטטיות - מחלקות מקוננות לא סטטיות. הם נקראים גם כיתות פנימיות בדרך אחרת.
  2. מחלקות מקוננות סטטיות - מחלקות מקוננות סטטיות.
בתורו, לשיעורים פנימיים יש שני תת-סוגים מיוחדים. מלבד העובדה שמעמד פנימי יכול להיות רק מעמד פנימי, זה יכול להיות גם:
  • כיתה מקומית
  • כיתה אנונימית
קצת קשה? :) זה בסדר, הנה תרשים לבהירות. חזור אליו במהלך ההרצאה אם ​​אתה פתאום מרגיש מבולבל! כיתות פנימיות מקוננות - 2בהרצאה של היום נדבר על מחלקות פנימיות – מחלקות פנימיות (הן גם מחלקות מקוננות לא סטטיות, מחלקות מקוננות לא סטטיות). הם מודגשים במיוחד בתרשים הכללי כדי שלא תלכו לאיבוד :) בואו נתחיל בשאלה המתבקשת: למה הכיתות האלה נקראות "פנימיות"? התשובה די פשוטה: מכיוון שהם נוצרים בתוך מחלקות אחרות. הנה דוגמה:
public class Bicycle {

   private String model;
   private int weight;

   public Bicycle(String model, int weight) {
       this.model = model;
       this.weight = weight;
   }

   public void start() {
       System.out.println("Go!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steering wheel to the right!");
       }

       public void left() {

           System.out.println("Steering wheel to the left!");
       }
   }

   public class Seat {

       public void up() {

           System.out.println("The seat is up!");
       }

       public void down() {

           System.out.println("The seat is down!");
       }
   }
}
כאן יש לנו חוג Bicycle- אופניים. יש לו 2 שדות ושיטה אחת - start(). כיתות פנימיות מקוננות - 3ההבדל שלו ממחלקה רגילה הוא שיש לו שתי מחלקות, שהקוד שלהן כתוב בפנים Bicycle- אלו המחלקות HandleBar(הגה) ו- Seat(מושב). אלה הם שיעורים מן המניין: כפי שאתה יכול לראות, לכל אחד מהם יש שיטות משלו. בשלב זה, ייתכן שתהיה לך שאלה: מדוע שמנו מחלקה אחת באחרת? למה לעשות אותם פנימיים? אוקיי, נניח שאנחנו צריכים כיתות נפרדות להגה ולמושב בתוכנית. אבל אתה לא צריך לקנן אותם! אתה יכול לעשות שיעורים רגילים. לדוגמה, כך:
public class HandleBar {
   public void right() {
       System.out.println("Steering wheel to the right!");
   }

   public void left() {

       System.out.println("Steering wheel left");
   }
}

public class Seat {

   public void up() {

       System.out.println("The seat is up!");
   }

   public void down() {

       System.out.println("The seat is down!");
   }
}
שאלה טובה מאוד! כמובן, אין לנו מגבלות טכניות - אנחנו יכולים לעשות את זה ככה. זה יותר על עיצוב כיתות נכון מנקודת המבט של תוכנית מסוימת ובמשמעות של אותה תוכנית. כיתות פנימיות הן שיעורים להדגשת ישות מסוימת בתוכנית הקשורה קשר בל יינתק עם ישות אחרת. הגה, מושב, דוושות הם המרכיבים של אופניים. בהפרדה מהאופניים הם לא הגיוניים. אם נהפוך את כל השיעורים הללו לשיעורים ציבוריים נפרדים, התוכנית שלנו יכולה לכלול, למשל, את הקוד הבא:
public class Main {

   public static void main(String[] args) {
       HandleBar handleBar = new HandleBar();
       handleBar.right();
   }
}
אמממ... את המשמעות של הקוד הזה אפילו קשה להסביר. יש לנו איזה כידון אופניים מוזר (למה זה נחוץ? אין מושג, למען האמת). וההגה הזה מסתובב ימינה... בכוחות עצמו, בלי אופניים... משום מה. על ידי הפרדת מהות ההגה ממהות האופניים, איבדנו את ההיגיון של התוכנית שלנו. באמצעות מחלקה פנימית, הקוד נראה שונה לחלוטין:
public class Main {

   public static void main(String[] args) {

       Bicycle peugeot = new Bicycle("Peugeot", 120);
       Bicycle.HandleBar handleBar = peugeot.new HandleBar();
       Bicycle.Seat seat = peugeot.new Seat();

       seat.up();
       peugeot.start();
       handleBar.left();
       handleBar.right();
   }
}
פלט מסוף:

Сиденье поднято выше!
Поехали!
Руль влево!
Руль вправо!
מה שקרה פתאום היה הגיוני! :) יצרנו חפץ לאופניים. יצרנו שניים מ"תת-האובייקטים" שלו - ההגה והמושב. הרמנו את המושב גבוה יותר מטעמי נוחות - ויצאנו לדרך: מתגלגלים ומנווטים לאן שצריך! :) השיטות שאנו צריכים נקראות על האובייקטים הדרושים. הכל פשוט ונוח. בדוגמה זו, הדגשת הכידון והמושב משפרת את המעטפת (אנחנו מסתירים נתונים על חלקי האופניים בתוך המחלקה המקבילה), ומאפשרת לנו ליצור הפשטה מפורטת יותר. עכשיו בואו נסתכל על מצב אחר. נניח שאנחנו רוצים ליצור תוכנית שמדגמנת חנות אופניים וחלקים. כיתות פנימיות מקוננות - 4במצב זה, הפתרון הקודם שלנו ייכשל. בגבולות חנות חלקים, לכל חלק בודד באופניים יש משמעות גם מלבד מהות האופניים. לדוגמה, נצטרך שיטות כמו "מכירת פדלים לקונה", "קניית מושב חדש" וכו'. זו תהיה טעות להשתמש כאן בשיעורים פנימיים - לכל חלק בודד באופניים במסגרת התוכנית החדשה שלנו יש משמעות משלו: הוא נפרד ממהות האופניים, ואינו קשור אליו בשום אופן. זה מה שאתה צריך לשים לב אם אתה תוהה אם אתה צריך להשתמש במחלקות פנימיות, או להפריד את כל הישויות למחלקות נפרדות. תכנות מונחה עצמים הוא נהדר מכיוון שהוא מקל על מודלים של ישויות בעולם האמיתי. זה מה שאתה יכול להשתמש כמדריך כשאתה מחליט אם להשתמש בשיעורים פנימיים. בחנות אמיתית חלקים נפרדים מאופניים - זה נורמלי. זה אומר שזה יהיה נכון בעת ​​תכנון תוכנית. אוקיי, סידרנו את ה"פילוסופיה" :) עכשיו בואו נכיר את התכונות ה"טכניות" החשובות של כיתות פנימיות. הנה מה שאתה בהחלט צריך לזכור ולהבין:
  1. אובייקט של מחלקה פנימית לא יכול להתקיים ללא אובייקט של מחלקה "חיצונית".

    זה הגיוני: בגלל זה הפכנו את זה לשיעורים Seatפנימיים HandleBar, כדי שגלגלי הגה ומושבים חסרי בעלים לא יופיעו פה ושם בתוכנית שלנו.

    הקוד הזה לא יקמפל:

    public static void main(String[] args) {
    
       HandleBar handleBar = new HandleBar();
    }

    התכונה החשובה הבאה נובעת מכך:

  2. לאובייקט של מחלקה פנימית יש גישה למשתנים של המחלקה "חיצונית".

    לדוגמה, בואו נוסיף Bicycleמשתנה לכיתה שלנו int seatPostDiameter- קוטר עמוד המושב.

    ואז בכיתה הפנימית Seatנוכל ליצור שיטה getSeatParam()שתגיד לנו את פרמטר המושב:

    public class Bicycle {
    
       private String model;
       private int weight;
    
       private int seatPostDiameter;
    
       public Bicycle(String model, int weight, int seatPostDiameter) {
           this.model = model;
           this.weight = weight;
           this.seatPostDiameter = seatPostDiameter;
    
       }
    
       public void start() {
           System.out.println("Go!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("The seat is up!");
           }
    
           public void down() {
    
               System.out.println("The seat is down!");
           }
    
           public void getSeatParam() {
    
               System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }

    ועכשיו אנחנו יכולים לקבל את המידע הזה בתוכנית שלנו:

    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
           Bicycle.Seat seat = bicycle.new Seat();
    
           seat.getSeatParam();
       }
    }

    פלט מסוף:

    
    Параметр сиденья: диаметр подседельного штыря = 40

    שים לב:המשתנה החדש מוצהר עם השינוי המחמיר ביותר - private. ועדיין למעמד הפנימי יש גישה!

  3. לא ניתן ליצור אובייקט מחלקה פנימית בשיטה סטטית של מחלקה "חיצונית".

    זה מוסבר על ידי תכונות העיצוב של כיתות פנימיות. למחלקה פנימית יכולים להיות בנאים עם פרמטרים או רק בנאי ברירת מחדל. אך ללא קשר לכך, כאשר אנו יוצרים אובייקט של המעמד הפנימי, מועברת אליו בשקט התייחסות לאובייקט של המעמד ה"חיצוני". אחרי הכל, נוכחות של אובייקט כזה היא תנאי מוקדם. אחרת לא נוכל ליצור אובייקטים של המעמד הפנימי.

    אבל אם שיטת המחלקה החיצונית היא סטטית, ייתכן שאובייקט המחלקה החיצונית לא קיים כלל! המשמעות היא שההיגיון של המעמד הפנימי יישבר. במצב כזה, המהדר יזרוק שגיאה:

    public static Seat createSeat() {
    
       //Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
  4. מחלקה פנימית אינה יכולה להכיל משתנים ושיטות סטטיות.

    ההיגיון כאן זהה: שיטות ומשתנים סטטיים יכולים להתקיים ולהיקרא גם אם אין אובייקט.

    אבל ללא אובייקט של המעמד ה"חיצוני", לא תהיה לנו גישה למעמד הפנימי.

    סתירה ברורה! לכן, הימצאות משתנים ושיטות סטטיות במחלקות פנימיות אסורה.

    המהדר יזרוק שגיאה בעת ניסיון ליצור אותם:

    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
    
           //inner class cannot have static declarations
           public static void getSeatParam() {
    
               System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
  5. בעת יצירת אובייקט של מחלקה פנימית, משנה הגישה שלו ממלא תפקיד חשוב.

    מחלקה פנימית יכולה להיות מסומנת על ידי משנה הגישה הסטנדרטית - public, private, protectedו package private.

    למה זה חשוב?

    זה משפיע על היכן בתוכנית שלנו נוכל ליצור את המעמד הפנימי.

    אם המחלקה שלנו Seatמוצהרת כ- public, נוכל ליצור את האובייקטים שלה בכל מחלקה אחרת. הדרישה היחידה היא שאובייקט של המחלקה "חיצונית" חייב להתקיים גם כן.

    אגב, כבר עשינו את זה כאן:

    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle peugeot = new Bicycle("Peugeot", 120);
           Bicycle.HandleBar handleBar = peugeot.new HandleBar();
           Bicycle.Seat seat = peugeot.new Seat();
    
           seat.up();
           peugeot.start();
           handleBar.left();
           handleBar.right();
       }
    }

    הגענו בקלות לכיתה הפנימית HandleBarמה- Main.

    אם נכריז על המחלקה הפנימית כ- private, תהיה לנו גישה רק ליצירת אובייקטים בתוך המחלקה "חיצונית".

    Seatלא נוכל יותר ליצור אובייקט מבחוץ:

    private class Seat {
    
       //methods
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           //Bicycle.Seat has a private access in 'Bicycle'
           Bicycle.Seat seat = bicycle.new Seat();
       }
    }

    בטח כבר הבנתם את ההיגיון :)

  6. משנה גישה למחלקות פנימיות פועלות כמו עבור משתנים רגילים.

    השינוי protectedמספק גישה למשתנה מחלקה במחלקות צאצאות שלו ובמחלקות שנמצאות באותה חבילה.

    אותו הדבר protectedעובד עבור כיתות פנימיות. ניתן ליצור אובייקטים protectedשל מחלקה פנימית :

    • בתוך המעמד ה"חיצוני";
    • בכיתות צאצאיו;
    • בשיעורים שנמצאים באותה חבילה.

    אם למחלקה הפנימית אין משנה גישה ( package private), ניתן ליצור אובייקטים של המחלקה הפנימית

    • בתוך המעמד ה"חיצוני";
    • בשיעורים שנמצאים באותה חבילה.

    אתה מכיר את השינויים כבר הרבה זמן, אז לא יהיו כאן בעיות.

זה הכל לבינתיים :) אבל אל תירגע! כיתות מקוננות פנימיות הן נושא רחב למדי שנמשיך לחקור בשיעורים הבאים. כעת תוכלו להתרענן בהרצאה על שיעורים פנימיים מהקורס שלנו. ובפעם הבאה נדבר על מחלקות מקוננות סטטיות.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION