CodeGym /Java-blogg /Tilfeldig /Eksempler på arv av nestede klasser
John Squirrels
Nivå
San Francisco

Eksempler på arv av nestede klasser

Publisert i gruppen
Hei! I dag skal vi se på en viktig mekanisme: arv i nestede klasser. Har du noen gang tenkt på hva du ville gjort hvis du trengte å få en nestet klasse til å arve en annen klasse. Hvis ikke, tro meg: denne situasjonen kan være forvirrende, fordi det er mange nyanser.
  1. Får vi en nestet klasse til å arve en eller annen klasse? Eller får vi en klasse til å arve en nestet klasse?
  2. Er barne-/foreldreklassen en vanlig offentlig klasse, eller er det også en nestet klasse?
  3. Til slutt, hvilken type nestede klasser bruker vi i alle disse situasjonene?
Det er så mange mulige svar på alle disse spørsmålene, hodet ditt vil snurre :) Som du vet kan vi løse et komplekst problem ved å dele det opp i enklere deler. La oss gjøre det. La oss vurdere hver gruppe nestede klasser etter tur fra to perspektiver: hvem som kan arve hver type nestede klasse, og hvem den kan arve. La oss starte med statiske nestede klasser.

Statiske nestede klasser

Eksempler på arv av nestede klasser - 2Deres arveregler er de enkleste. Her kan du gjøre nesten alt du måtte ønske. En statisk nestet klasse kan arve:
  • en vanlig klasse
  • en statisk nestet klasse som er deklarert i en ytre klasse eller dens forfedre
Husk et eksempel fra leksjonen vår om statiske nestede 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;
       }
   }
}
La oss prøve å endre koden og lage en Drawingstatisk nestet klasse og dens etterkommer - 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, ikke noe problem. Vi kan til og med trekke ut Drawingklassen og gjøre den til en vanlig offentlig klasse i stedet for en statisk nestet klasse - ingenting vil endre seg.

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 forstår dette. Men hvilke klasser kan arve en statisk nestet klasse? Praktisk talt alle! Nestet/ikke-nestet, statisk/ikke-statisk — det spiller ingen rolle. Her får vi den Boeing737Drawingindre klassen til å arve den Drawingstatiske nestede 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 lage en forekomst av Boeing737Drawingslik:

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

   }

}
Selv om klassen vår Boeing737Drawingarver en statisk klasse, er den ikke statisk i seg selv! Som et resultat vil den alltid trenge en forekomst av den ytre klassen. Vi kan fjerne Boeing737Drawingklassen fra Boeing737klassen og gjøre den til en enkel offentlig klasse. Ingenting endrer seg. Den kan fortsatt arve den Drawingstatiske nestede 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;
   
}
Det eneste viktige poenget er at i dette tilfellet må vi gjøre den statiske maxPassengersCountvariabelen offentlig. Hvis det forblir privat, vil ikke en vanlig offentlig klasse ha tilgang til det. Vi har funnet ut statiske klasser! :) La oss nå gå videre til indre klasser. De kommer i 3 typer: enkle indre klasser, lokale klasser og anonyme indre klasser. Eksempler på arv av nestede klasser - 3Igjen, la oss gå fra enkelt til komplekst :)

Anonyme indre klasser

En anonym indre klasse kan ikke arve en annen klasse. Ingen annen klasse kan arve en anonym klasse. Det kunne ikke vært enklere! :)

Lokale klasser

Lokale klasser (i tilfelle du har glemt det) er deklarert i en kodeblokk av en annen klasse. Oftest skjer dette innenfor en eller annen metode i den ytre klassen. Logisk sett kan bare andre lokale klasser innenfor samme metode (eller kodeblokk) arve en lokal klasse. Her er et eksempel:

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
   }
}
Dette er koden fra leksjonen vår om lokale klasser. Vår nummervalideringsklasse har en PhoneNumberlokal klasse. Hvis vi trenger det for å representere to forskjellige enheter, for eksempel et mobiltelefonnummer og et fasttelefonnummer, kan vi bare gjøre dette innenfor samme metode. Årsaken er enkel: en lokal klasses omfang er begrenset til metoden (kodeblokken) der den er deklarert. Som et resultat vil vi ikke kunne bruke den eksternt (inkludert for klassearv). Mulighetene for arv innenfor selve lokalklassen er imidlertid mye bredere! En lokal klasse kan arve:
  1. En vanlig klasse.
  2. En indre klasse som er erklært i samme klasse som den lokale klassen eller i en av dens forfedre.
  3. En annen lokal klasse erklært i samme metode (kodeblokk).
Det første og tredje punktet ser åpenbart ut, men det andre er litt forvirrende :/ La oss se på to eksempler. Eksempel 1 - "Å få en lokal klasse til å arve en indre klasse som er erklært i samme klasse som den lokale 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
   }
}
Her fjernet vi PhoneNumberklassen fra validatePhoneNumber()metoden og gjorde den til en indre klasse i stedet for en lokal klasse. Dette hindrer oss ikke i å få våre 2 lokale klasser til å arve den. Eksempel 2 - "... eller i forfedrene til denne klassen." Nå er dette allerede mer interessant. Vi kan rykke PhoneNumberenda høyere i arvekjeden. La oss erklære en abstrakt AbstractPhoneNumberValidatorklasse, som vil bli stamfaren til PhoneNumberValidatorklassen vår:

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, erklærte vi det ikke bare – vi flyttet også den PhoneNumberindre klassen inn i det. Men i sin etterkommer PhoneNumberValidatorkan lokale klasser deklarert i metoder arve PhoneNumberuten problemer!

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å grunn av arveforholdet "ser" de lokale klassene i en etterkommerklasse de indre klassene inne i en stamfar. Og til slutt, la oss gå videre til den siste gruppen :)

Indre klasser

En indre klasse erklært i samme ytre klasse (eller i dens etterkommer) kan arve en annen indre klasse. La oss utforske dette ved å bruke vårt eksempel med sykler fra leksjonen om indre 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
   }
}
Her erklærte vi den Seatindre klassen inne i Bicycleklassen. En spesiell type racersete, SportSeat, arver det. Men vi kan lage en egen "racersykkel"-type og sette den i en egen klasse:

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!");
       }
   }
}
Dette er også et alternativ. Den indre klassen til etterkommeren ( SportBicycle.SportSeat) "ser" de indre klassene til forfaren og kan arve dem. Å arve indre klasser har en veldig viktig egenskap! I de to foregående eksemplene SportSeatvar klassen vår en indre klasse. Men hva om vi bestemmer oss for å lage SportSeaten vanlig offentlig klasse som samtidig arver den Seatindre 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 fikk en feil! Kan du gjette hvorfor? :) Det hele er enkelt. Da vi snakket om den Bicycle.Seatindre klassen, nevnte vi at en referanse til en forekomst av den ytre klassen implisitt overføres til konstruktøren av den indre klassen. Dette betyr at du ikke kan lage et Seatobjekt uten å lage et Bicycleobjekt. Men hva med opprettelsen av en SportSeat? I motsetning til Seat, har den ikke denne innebygde mekanismen for implisitt å sende konstruktøren en referanse til en forekomst av den ytre klassen. S till, uten et Bicycleobjekt, kan vi ikke lage et SportSeatobjekt, akkurat som i tilfellet med Seat. Derfor er det bare én ting igjen for oss å gjøre - eksplisitt gi konstruktøren SportSeaten referanse til et Bicycleobjekt. Slik gjør du det:

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 kaller superklassekonstruktøren ved å bruke super(); Now, hvis vi ønsker å lage et SportSeatobjekt, vil ingenting stoppe oss fra å gjøre dette:

public class Main {

   public static void main(String[] args) {

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

   }
}
Puh! Denne leksjonen var ganske lang :) Men du lærte mye! Nå er det på tide å løse noen oppgaver! :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION