CodeGym /Java blog /Véletlen /Beágyazott belső osztályok
John Squirrels
Szint
San Francisco

Beágyazott belső osztályok

Megjelent a csoportban
Szia! Ma egy fontos témával foglalkozunk: hogyan működnek a beágyazott osztályok a Java-ban. A Java lehetővé teszi osztályok létrehozását egy másik osztályon belül:

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
Ezeket a belső osztályokat beágyazottnak nevezzük. 2 típusra oszthatók:
  1. Nem statikus beágyazott osztályok. Ezeket belső osztályoknak is nevezik.
  2. Statikus beágyazott osztályok.
A belső osztályoknak viszont két különálló alkategóriája van. Amellett, hogy egy belső osztály egyszerűen belső osztály, lehet:
  • egy helyi osztály
  • egy névtelen osztály
Zavaros? :) Rendben van. Itt van egy diagram az egyértelműség kedvéért. Térjen vissza az óra alatt, ha hirtelen összezavarodik! Beágyazott belső osztályok – 2A mai leckében a belső osztályokról (más néven nem statikus beágyazott osztályokról) fogunk beszélni. Az általános diagramon külön kiemelve vannak, hogy ne tévedj el :) Kezdjük a nyilvánvaló kérdéssel: miért nevezik őket "belső" osztályoknak? A válasz nagyon egyszerű: mert más osztályokon belül jönnek létre. Íme egy példa:

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("Let's go!");
   }

   public class Handlebar {

       public void right() {
           System.out.println("Steer right!");
       }

       public void left() {

           System.out.println("Steer left!");
       }
   }

   public class Seat {
      
       public void up() {

           System.out.println("Seat up!");
       }
      
       public void down() {

           System.out.println("Seat down!");
       }
   }
}
Itt van az Bicycleosztály. 2 mezője és 1 metódusa van: start(). Beágyazott belső osztályok - 3Abban különbözik a közönséges osztálytól, hogy két osztályt tartalmaz: Handlebarés Seat. A kódjuk az osztályon belül van írva Bicycle. Ezek teljes értékű osztályok: mint látható, mindegyiknek megvan a maga módszere. Ezen a ponton felmerülhet a kérdés: mi a fenéért helyeznénk el egyik osztályt a másikba? Miért kell őket belső osztályokká tenni? Nos, tegyük fel, hogy külön osztályokra van szükségünk a programunkban a kormány és az ülés fogalmához. Természetesen nem szükséges, hogy beágyazzuk őket! Készíthetünk rendes órákat. Például így:

public class Handlebar {
   public void right() {
       System.out.println("Steer right!");
   }

   public void left() {

       System.out.println("Steer left");
   }
}

public class Seat {

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
Nagyon jó kérdés! Természetesen nem korlátoz minket a technológia. Ez természetesen egy lehetőség. Itt inkább az órák helyes kialakítása az adott program és annak célja szempontjából a fontos. A belső osztályok egy olyan entitás elkülönítésére szolgálnak, amely elválaszthatatlanul kapcsolódik egy másik entitáshoz. A kormány, az ülések és a pedálok a kerékpár részei. A biciklitől elválasztva nincs sok értelmük. Ha ezeket a fogalmakat külön nyilvános osztályokká tesszük, akkor a programunkban a következő kódot kaptuk volna:

public class Main {

   public static void main(String[] args) {
       Handlebar handlebar = new Handlebar();
       handlebar.right();
   }
}
Hmm... Ennek a kódnak a jelentését még nehéz megmagyarázni. Van egy bizonytalan kormányunk (miért van rá szükség? Fogalmam sincs, hogy őszinte legyek). És ez a fogantyú jobbra fordul... magától, bicikli nélkül... valamiért. A kormány és a kerékpár fogalmának elválasztásával némi logikát veszítettünk programunkból. Egy belső osztály használatával a kód nagyon eltérően néz ki:

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();
   }
}
Konzol kimenet:

Seat up! 
Let's go! 
Steer left! 
Steer right!
Most, amit látunk, hirtelen értelmet nyer! :) Bicikli objektumot alkottunk. Létrehoztunk két kerékpáros "altárgyat" - egy kormányt és egy ülést. Felemeltük az ülést a kényelem kedvéért, és indultunk is: pedálozunk és kormányozunk, ahogy kellett! :) A szükséges metódusokat a megfelelő objektumokon hívjuk meg. Mindez egyszerű és kényelmes. Ebben a példában a kormány és az ülés szétválasztása javítja a tokozást (az adott osztályon belül elrejti a kerékpáralkatrészek adatait), és lehetővé teszi egy részletesebb absztrakció létrehozását. Most nézzünk egy másik helyzetet. Tegyük fel, hogy szeretnénk létrehozni egy programot, amely szimulál egy kerékpárboltot és a kerékpárok alkatrészeit. Beágyazott belső osztályok - 4Ebben a helyzetben a korábbi megoldásunk nem működik. Egy kerékpárboltban minden egyes kerékpáralkatrésznek van értelme még akkor is, ha elválasztják a kerékpártól. Például szükségünk lesz olyan módszerekre, mint a „pedálok eladása az ügyfélnek”, „új ülés vásárlása”, stb. Hiba lenne itt belső osztályokat használni – új programunkban minden egyes kerékpár alkatrésznek van jelentése, amely megállja a helyét. sajátja: elválasztható a kerékpár fogalmától. Pontosan erre kell figyelnie, ha arra gondol, hogy belső osztályokat kell-e használnia, vagy az összes entitást külön osztályként kell-e szerveznie. Az objektum-orientált programozás abban jó, hogy egyszerűvé teszi a valós entitások modellezését. Ez lehet a vezérelv a belső osztályok használatának eldöntésekor. Egy igazi boltban, a pótalkatrészek külön vannak a kerékpároktól – ez rendben van. Ez azt jelenti, hogy programtervezéskor is rendben van. Oké, kitaláltuk a "filozófiát" :) Most ismerkedjünk meg a belső órák fontos "technikai" jellemzőivel. Íme, amit feltétlenül emlékezned kell és meg kell értened:
  1. Egy belső osztály objektuma nem létezhet egy külső osztály objektuma nélkül.

    Ez logikus: ezért készítettük el programunkban a Seatés a belső osztályokat – hogy ne kerüljön elárvult kormány és ülés.Handlebar

    Ez a kód nem fordítja le:

    
    public static void main(String[] args) {
    
       Handlebar handlebar = new Handlebar();
    }
    

    Ebből egy másik fontos jellemző következik:

  2. Egy belső osztály objektuma hozzáfér a külső osztály változóihoz.

    Például adjunk hozzá egy int seatPostDiameterváltozót (amely a nyeregcső átmérőjét jelenti) az osztályunkhoz Bicycle.

    Ezután a Seatbelső osztályban létrehozhatunk egy displaySeatProperties()metódust, amely megjeleníti az ülés tulajdonságait:

    
    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("Let's go!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("Seat up!");
           }
    
           public void down() {
    
               System.out.println("Seat down!");
           }
    
           public void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
    

    És most ezt az információt megjeleníthetjük a programunkban:

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

    Konzol kimenet:

    
    Seat properties: seatpost diameter = 40
    

    Jegyzet:az új változót a legszigorúbb hozzáférésmódosítóval ( private) deklaráljuk. És még mindig a belső osztálynak van hozzáférése!

  3. Egy belső osztály objektuma nem hozható létre egy külső osztály statikus metódusában.

    Ezt a belső osztályok megszervezésének sajátosságai magyarázzák. Egy belső osztály rendelkezhet paraméterekkel rendelkező konstruktorokkal, vagy csak az alapértelmezett konstruktorral. De ettől függetlenül, amikor létrehozunk egy belső osztály objektumát, a külső osztály objektumára való hivatkozás láthatatlanul átkerül a belső osztály létrehozott objektumához. Hiszen egy ilyen tárgyreferencia megléte abszolút követelmény. Ellenkező esetben nem tudjuk létrehozni a belső osztály objektumait.

    De ha a külső osztály metódusa statikus, akkor lehet, hogy nem lesz a külső osztály objektuma! És ez sértené a belső osztály működésének logikáját. Ebben a helyzetben a fordító hibát generál:

    
    public static Seat createSeat() {
      
       // Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
    
  4. Egy belső osztály nem tartalmazhat statikus változókat és metódusokat.

    A logika ugyanaz: statikus metódusok és változók létezhetnek, és objektum hiányában is hívhatók vagy hivatkozhatnak rájuk.

    De a külső osztály objektuma nélkül nem lesz hozzáférésünk a belső osztályhoz.

    Egyértelmű ellentmondás! Ez az oka annak, hogy a statikus változók és metódusok nem megengedettek a belső osztályokban.

    A fordító hibát generál, ha megpróbálja létrehozni őket:

    
    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
          
           // An inner class cannot have static declarations
           public static void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
    
  5. Egy belső osztály objektumának létrehozásakor fontos a hozzáférés módosítója.

    Egy belső osztályt a standard hozzáférés módosítókkal lehet megjelölni: public, private, protected, és package private.

    Miért számít ez?

    Ez befolyásolja, hogy a programunkban hol hozhatunk létre példányokat a belső osztályból.

    Ha az Seatosztályunk a következővel van deklarálva , akkor bármely más osztályban publiclétrehozhatunk objektumokat. SeatAz egyetlen követelmény az, hogy a külső osztály objektumának is léteznie kell.

    Egyébként ezt már megtettük itt:

    
    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();
       }
    }
    

    Az osztályból könnyen bejutottunk a Handlebarbelső osztályba Main.

    Ha a belső osztályt -nak deklaráljuk private, akkor csak a külső osztályon belül tudunk objektumokat létrehozni.

    Seat"Kívülről" már nem tudunk objektumot létrehozni :

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

    Valószínűleg már érted a logikát :)

  6. A belső osztályokhoz tartozó hozzáférés-módosítók ugyanúgy működnek, mint a közönséges változók esetében.

    A protectedmódosító hozzáférést biztosít egy példányváltozóhoz azokban az alosztályokban és osztályokban, amelyek ugyanabban a csomagban vannak.

    protectedbelső osztályokra is működik. Létrehozhatunk protectedobjektumokat a belső osztályból:

    • a külső osztályban;
    • alosztályaiban;
    • osztályokban, amelyek ugyanabban a csomagban vannak.

    Ha a belső osztály nem rendelkezik hozzáférésmódosítóval ( package private), akkor a belső osztály objektumai létrehozhatók:

    • a külső osztályban;
    • osztályokban, amelyek ugyanabban a csomagban vannak.

    Régóta ismeri a módosítókat, így nincs probléma.

Egyelőre ennyi :) De ne lazsálj! A belső osztályok meglehetősen kiterjedt téma, amelyet a következő leckében folytatunk. Most felfrissítheti az emlékezetét tanfolyamunk belső osztályairól szóló órájáról . És legközelebb beszéljünk a statikus beágyazott osztályokról.
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION