CodeGym/Java blogg/Slumpmässig/Exempel på nedärvning av kapslade klasser
John Squirrels
Nivå
San Francisco

Exempel på nedärvning av kapslade klasser

Publicerad i gruppen
Hej! Idag ska vi titta på en viktig mekanism: arv i kapslade klasser. Har du någonsin tänkt på vad du skulle göra om du behövde få en kapslad klass att ärva någon annan klass. Om inte, tro mig: den här situationen kan vara förvirrande, eftersom det finns många nyanser.
  1. Får vi en kapslad klass att ärva någon klass? Eller får vi någon klass att ärva en kapslad klass?
  2. Är barn-/förälderklassen en vanlig offentlig klass, eller är det också en kapslad klass?
  3. Slutligen, vilken typ av kapslade klasser använder vi i alla dessa situationer?
Det finns så många möjliga svar på alla dessa frågor, ditt huvud snurrar :) Som du vet kan vi lösa ett komplext problem genom att dela upp det i enklare delar. Låt oss göra det. Låt oss betrakta varje grupp av kapslade klasser i tur och ordning ur två perspektiv: vem som kan ärva varje typ av kapslad klass och vem den kan ärva. Låt oss börja med statiska kapslade klasser.

Statiska kapslade klasser

Exempel på nedärvning av kapslade klasser - 2Deras arvsregler är de enklaste. Här kan du göra nästan allt du kan önska. En statisk kapslad klass kan ärva:
  • en vanlig klass
  • en statisk kapslad klass som deklareras i en yttre klass eller dess förfäder
Kom ihåg ett exempel från vår lektion om statiska kapslade klasser.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Låt oss försöka ändra koden och skapa en Drawingstatisk kapslad klass och dess avkomling — Boeing737Drawing.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Som du kan se, inga problem. Vi kan till och med dra ut Drawingklassen och göra den till en vanlig offentlig klass istället för en statisk kapslad klass - ingenting kommer att förändras.
public class Drawing {

}

public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Vi förstår detta. Men vilka klasser kan ärva en statisk kapslad klass? Praktiskt taget vilken som helst! Kapslad/icke-kapslad, statisk/icke-statisk — det spelar ingen roll. Här får vi den Boeing737Drawinginre klassen att ärva den Drawingstatiska kapslade klassen:
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public class Boeing737Drawing extends Drawing {

       public int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Du kan skapa en instans av Boeing737Drawingså här:
public class Main {

   public static void main(String[] args) {

      Boeing737 boeing737 = new Boeing737(1990);
      Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
      System.out.println(drawing.getMaxPassengersCount());

   }

}
Även om vår Boeing737Drawingklass ärver en statisk klass, är den inte statisk i sig! Som ett resultat kommer det alltid att behöva en instans av den yttre klassen. Vi kan ta bort Boeing737Drawingklassen från Boeing737klassen och göra den till en enkel offentlig klass. Inget ändras. Den kan fortfarande ärva den Drawingstatiska kapslade klassen.
public class Boeing737 {

   private int manufactureYear;
   public static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }
}

public class Boeing737Drawing extends Boeing737.Drawing {

   public int getMaxPassengersCount() {

       return Boeing737.maxPassengersCount;

}
Den enda viktiga punkten är att vi i det här fallet måste göra den statiska maxPassengersCountvariabeln offentlig. Om det förblir privat, kommer en vanlig offentlig klass inte att ha tillgång till det. Vi har listat ut statiska klasser! :) Låt oss nu gå vidare till inre klasser. De finns i 3 typer: enkla inre klasser, lokala klasser och anonyma inre klasser. Exempel på nedärvning av kapslade klasser - 3Återigen, låt oss gå från enkla till komplexa :)

Anonyma inre klasser

En anonym inre klass kan inte ärva en annan klass. Ingen annan klass kan ärva en anonym klass. Det kan inte bli enklare! :)

Lokala klasser

Lokala klasser (om du har glömt) deklareras i ett kodblock av en annan klass. Oftast händer detta inuti någon metod i den yttre klassen. Logiskt sett kan bara andra lokala klasser inom samma metod (eller kodblock) ärva en lokal klass. Här är ett exempel:
public class PhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       class CellPhoneNumber extends PhoneNumber {

       }

       class LandlinePhoneNumber extends PhoneNumber {


       }

       // ...number validation code
   }
}
Det här är koden från vår lektion om lokala klasser. Vår nummervalideringsklass har en PhoneNumberlokal klass. Om vi ​​behöver det för att representera två distinkta enheter, till exempel ett mobiltelefonnummer och ett fast telefonnummer, kan vi bara göra detta inom samma metod. Anledningen är enkel: en lokal klasss omfattning är begränsad till metoden (kodblocket) där den deklareras. Som ett resultat kommer vi inte att kunna använda det externt (inklusive för klassarv). Möjligheterna till arv inom själva lokalklassen är dock mycket bredare! En lokal klass kan ärva:
  1. En vanlig klass.
  2. En inre klass som deklareras i samma klass som den lokala klassen eller i någon av dess förfäder.
  3. En annan lokal klass deklareras i samma metod (kodblock).
Den första och tredje punkten ser självklar ut, men den andra är lite förvirrande :/ Låt oss titta på två exempel. Exempel 1 — "Att få en lokal klass att ärva en inre klass som deklareras i samma klass som den lokala klassen":
public class PhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       // ...number validation code
   }
}
Här tog vi bort PhoneNumberklassen från validatePhoneNumber()metoden och gjorde den till en inre klass istället för en lokal klass. Detta hindrar oss inte från att få våra två lokala klasser att ärva det. Exempel 2 — "... eller i denna klasss förfäder." Nu är detta redan mer intressant. Vi kan flytta PhoneNumberännu högre i arvskedjan. Låt oss förklara en abstrakt klass, som kommer att bli vår klasss AbstractPhoneNumberValidatorförfader :PhoneNumberValidator
public abstract class AbstractPhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

}
Som du kan se deklarerade vi det inte bara – vi flyttade också in den PhoneNumberinre klassen till det. Men i dess efterkommande PhoneNumberValidatorkan lokala klasser som deklarerats i metoder ärva PhoneNumberutan problem!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       // ...number validation code
   }
}
På grund av arvsförhållandet "ser" de lokala klasserna i en ättlingklass de inre klasserna inuti en förfader. Och slutligen, låt oss gå vidare till den sista gruppen :)

Inre klasser

En inre klass som deklareras i samma yttre klass (eller i dess avkomling) kan ärva en annan inre klass. Låt oss utforska detta med vårt exempel med cyklar från lektionen om inre klasser.
public class Bicycle {

   private String model;
   private int maxWeight;

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

   public void start() {
       System.out.println("Let's go!");
   }

   class Seat {

       public void up() {

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

       public void down() {

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

   class SportSeat extends Seat {

       // ...methods
   }
}
Här förklarade vi den Seatinre klassen inne i Bicycleklassen. En speciell typ av racingstol, , SportSeatärver den. Men vi skulle kunna skapa en separat "racingcykel"-typ och placera den i en separat klass:
public class SportBicycle extends Bicycle {

   public SportBicycle(String model, int maxWeight) {
       super(model, maxWeight);
   }


   class SportSeat extends Seat {

       public void up() {

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

       public void down() {

           System.out.println("Seat down!");
       }
   }
}
Detta är också ett alternativ. Den inre klassen hos efterkommande ( SportBicycle.SportSeat) "ser" förfaderns inre klasser och kan ärva dem. Att ärva inre klasser har en mycket viktig egenskap! I de två föregående exemplen SportSeatvar vår klass en inre klass. Men tänk om vi bestämmer oss för att göra SportSeaten vanlig offentlig klass som samtidigt ärver den Seatinre klassen?
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

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

   public void down() {

       System.out.println("Seat down!");
   }
}
Vi fick ett fel! Kan du gissa varför? :) Allt är okomplicerat. När vi pratade om den Bicycle.Seatinre klassen nämnde vi att en referens till en instans av den yttre klassen implicit skickas till konstruktören av den inre klassen. Det betyder att du inte kan skapa ett Seatobjekt utan att skapa ett Bicycleobjekt. Men hur är det med skapandet av en SportSeat? Till skillnad från Seat, har den inte denna inbyggda mekanism för att implicit skicka konstruktorn en referens till en instans av den yttre klassen. S till, utan ett Bicycleobjekt, kan vi inte skapa ett SportSeatobjekt, precis som i fallet med Seat. Därför finns det bara en sak kvar för oss att göra - att uttryckligen skicka SportSeaten referens till ett Bicycleobjekt till konstruktören. Så här gör du:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

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

   public void down() {

       System.out.println("Seat down!");
   }
}
Vi kallar superklassens konstruktor med hjälp av super(); Now, om vi vill skapa ett SportSeatobjekt, kommer ingenting att hindra oss från att göra detta:
public class Main {

   public static void main(String[] args) {

       Bicycle bicycle = new Bicycle("Peugeot", 120);
       SportSeat peugeotSportSeat = new SportSeat(bicycle);

   }
}
Puh! Den här lektionen var ganska lång :) Men du lärde dig mycket! Nu är det dags att lösa några uppgifter! :)
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