CodeGym/Java blogg/Slumpmässig/Kapslade inre klasser
John Squirrels
Nivå
San Francisco

Kapslade inre klasser

Publicerad i gruppen
Hej! Idag ska vi ta upp ett viktigt ämne - hur kapslade klasser fungerar i Java. Java låter dig skapa klasser i en annan klass:
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
Dessa interna klasser kallas kapslade. De är indelade i 2 typer:
  1. Icke-statiska kapslade klasser. Dessa kallas också inre klasser.
  2. Statiska kapslade klasser.
I sin tur har inre klasser två distinkta underkategorier. Förutom att en inre klass helt enkelt är en inre klass kan det också vara:
  • en lokal klass
  • en anonym klass
Förvirrad? :) Det är okej. Här är ett diagram för tydlighetens skull. Kom tillbaka till det under lektionen om du plötsligt blir förvirrad! Kapslade inre klasser - 2I dagens lektion kommer vi att diskutera inre klasser (även kända som icke-statiska kapslade klasser). De är speciellt framhävda i det övergripande diagrammet så att du inte går vilse :) Låt oss börja med den uppenbara frågan: varför kallas de för "inre" klasser? Svaret är ganska enkelt: eftersom de skapas i andra klasser. Här är ett exempel:
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!");
       }
   }
}
Här har vi Bicycleklassen. Den har 2 fält och 1 metod: start(). Kapslade inre klasser - 3Den skiljer sig från en vanlig klass genom att den innehåller två klasser: Handlebaroch Seat. Deras kod är skriven i Bicycleklassen. Dessa är fullfjädrade klasser: som du kan se har var och en av dem sina egna metoder. Vid det här laget kanske du har en fråga: varför i hela friden skulle vi placera en klass i en annan? Varför göra dem till inre klasser? Tja, anta att vi behöver separata klasser för begreppen styre och säte i vårt program. Naturligtvis är det inte nödvändigt för oss att göra dem kapslade! Vi kan göra vanliga klasser. Till exempel, så här:
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!");
   }
}
Mycket bra fråga! Naturligtvis är vi inte begränsade av tekniken. Att göra det är definitivt ett alternativ. Här är det viktiga mer den korrekta utformningen av klasserna utifrån ett specifikt program och dess syfte. Inre klasser är till för att separera en entitet som är oupplösligt kopplad till en annan entitet. Styre, säten och pedaler är komponenter i en cykel. Separerade från cykeln gör de inte så mycket mening. Om vi ​​gjort alla dessa begrepp separata offentliga klasser, skulle vi ha haft koden så här i vårt program:
public class Main {

   public static void main(String[] args) {
       Handlebar handlebar = new Handlebar();
       handlebar.right();
   }
}
Hmm... Innebörden av den här koden är till och med svår att förklara. Vi har ett vagt styre (Varför är det nödvändigt? Ingen aning om jag ska vara ärlig). Och det här handtaget svänger höger... helt av sig självt, utan cykel... av någon anledning. Genom att skilja konceptet med styret från konceptet med cykeln tappade vi lite logik i vårt program. Med en inre klass ser koden väldigt annorlunda ut:
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();
   }
}
Konsolutgång:
Seat up!
Let's go!
Steer left!
Steer right!
Nu är det vi ser plötsligt vettigt! :) Vi skapade ett cykelobjekt. Vi skapade två "delobjekt" för cykel - ett styre och ett säte. Vi höjde sätet för komfort och iväg: trampade och styrde efter behov! :) Metoderna vi behöver anropas på lämpliga objekt. Det hela är enkelt och bekvämt. I det här exemplet förbättrar separeringen av styret och sätet inkapslingen (vi döljer data om cykeldelarna i den relevanta klassen) och låter oss skapa en mer detaljerad abstraktion. Låt oss nu titta på en annan situation. Anta att vi vill skapa ett program som simulerar en cykelaffär och reservdelar till cyklar. Kapslade inre klasser - 4I det här läget kommer vår tidigare lösning inte att fungera. I en cykelaffär är varje enskild cykeldel vettig även när den är åtskild från en cykel. Vi kommer till exempel att behöva metoder som "sälja pedaler till en kund", "köpa en ny stol" etc. Det skulle vara ett misstag att använda inre klasser här — varje enskild cykeldel i vårt nya program har betydelse som står på sin egen: den kan skiljas från begreppet cykel. Detta är precis vad du behöver vara uppmärksam på om du undrar om du ska använda inre klasser eller organisera alla enheter som separata klasser. Objektorienterad programmering är bra eftersom det gör det enkelt att modellera verkliga enheter. Detta kan vara din vägledande princip när du bestämmer dig för om du ska använda inre klasser. I en riktig butik, reservdelar är separata från cyklar — det här är okej. Det betyder att det också är okej när man designar ett program. Okej, vi har listat ut "filosofin" :) Låt oss nu bekanta oss med viktiga "tekniska" egenskaper hos inre klasser. Här är vad du definitivt behöver komma ihåg och förstå:
  1. Ett objekt av en inre klass kan inte existera utan ett objekt av en yttre klass.

    Detta är vettigt: det är därför vi skapade klasserna Seatoch Handlebarinre klasserna i vårt program - så att vi inte slutar med föräldralösa styre och säten.

    Denna kod kompilerar inte:

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

    En annan viktig egenskap följer av detta:

  2. Ett objekt i en inre klass har tillgång till variablerna för den yttre klassen.

    Låt oss till exempel lägga till en int seatPostDiametervariabel (som representerar sadelstolpens diameter) till vår Bicycleklass.

    Sedan i den Seatinre klassen kan vi skapa en displaySeatProperties()metod som visar sätesegenskaperna:

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

    Och nu kan vi visa denna information i vårt program:

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

    Konsolutgång:

    Seat properties: seatpost diameter = 40

    Notera:den nya variabeln deklareras med den mest strikta åtkomstmodifieraren ( private). Och ändå har den inre klassen tillgång!

  3. Ett objekt av en inre klass kan inte skapas i en statisk metod för en yttre klass.

    Detta förklaras av de specifika egenskaperna hos hur inre klasser är organiserade. En inre klass kan ha konstruktorer med parametrar, eller bara standardkonstruktorn. Men oavsett, när vi skapar ett objekt av en inre klass, överförs en referens till objektet för den yttre klassen osynligt till det skapade objektet av den inre klassen. När allt kommer omkring är närvaron av en sådan objektreferens ett absolut krav. Annars kommer vi inte att kunna skapa objekt av den inre klassen.

    Men om en metod för den yttre klassen är statisk, så kanske vi inte har ett objekt av den yttre klassen! Och detta skulle vara ett brott mot logiken i hur en inre klass fungerar. I den här situationen kommer kompilatorn att generera ett fel:

    public static Seat createSeat() {
    
       // Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
  4. En inre klass kan inte innehålla statiska variabler och metoder.

    Logiken är densamma: statiska metoder och variabler kan existera och anropas eller refereras även i frånvaro av ett objekt.

    Men utan ett objekt från den yttre klassen kommer vi inte att ha tillgång till den inre klassen.

    En klar motsägelse! Det är därför statiska variabler och metoder inte är tillåtna i inre klasser.

    Kompilatorn kommer att generera ett fel om du försöker skapa dem:

    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. När du skapar ett objekt av en inre klass är dess åtkomstmodifierare viktig.

    En inre klass kan märkas med standardåtkomstmodifierarna: public, private, protected, och package private.

    Varför spelar detta roll?

    Detta påverkar var vi kan skapa instanser av den inre klassen i vårt program.

    Om vår Seatklass deklareras som public, kan vi skapa Seatobjekt i vilken annan klass som helst. Det enda kravet är att ett objekt av den yttre klassen också måste finnas.

    Förresten, vi har redan gjort det här:

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

    Vi fick lätt tillgång till den Handlebarinre klassen från Mainklassen.

    Om vi ​​deklarerar den inre klassen som private, kommer vi att kunna skapa objekt endast inom den yttre klassen.

    Vi kan inte längre skapa ett Seatobjekt "på utsidan":

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

    Du förstår säkert redan logiken :)

  6. Åtkomstmodifierare för inre klasser fungerar på samma sätt som för vanliga variabler.

    Modifieraren protectedger tillgång till en instansvariabel i underklasser och klasser som finns i samma paket.

    protectedfungerar även för inre klasser. Vi kan skapa protectedobjekt av den inre klassen:

    • i den yttre klassen;
    • i dess underklasser;
    • i klasser som är i samma paket.

    Om den inre klassen inte har en åtkomstmodifierare ( package private), kan objekt av den inre klassen skapas:

    • i den yttre klassen;
    • i klasser som är i samma paket.

    Du har varit bekant med modifierare länge, så inga problem här.

Det var allt för nu :) Men slappa inte av! Inre klasser är ett ganska omfattande ämne som vi kommer att fortsätta att utforska i nästa lektion. Nu kan du fräscha upp ditt minne av vår kurss lektion om inre klasser . Och nästa gång, låt oss prata om statiska kapslade klasser.
Kommentarer
  • Populär
  • Ny
  • Gammal
Du måste vara inloggad för att lämna en kommentar
Den här sidan har inga kommentarer än