CodeGym /Java Blog /Willekeurig /Voorbeelden van overerving van geneste klassen
John Squirrels
Niveau 41
San Francisco

Voorbeelden van overerving van geneste klassen

Gepubliceerd in de groep Willekeurig
Hoi! Vandaag kijken we naar een belangrijk mechanisme: overerving in geneste klassen. Heb je er ooit over nagedacht wat je zou doen als je een geneste klasse een andere klasse zou laten erven? Zo niet, geloof me: deze situatie kan verwarrend zijn, omdat er veel nuances zijn.
  1. Laten we een geneste klasse een bepaalde klasse erven? Of laten we een klasse een geneste klasse erven?
  2. Is de child/parent-klasse een gewone openbare klasse of is het ook een geneste klasse?
  3. Tot slot, welk type geneste klassen gebruiken we in al deze situaties?
Er zijn zoveel mogelijke antwoorden op al deze vragen, je hoofd zal ervan tollen :) Zoals je weet, kunnen we een complex probleem oplossen door het op te splitsen in eenvoudigere delen. Laten we dat doen. Laten we elke groep geneste klassen achtereenvolgens vanuit twee perspectieven bekijken: wie kan elk type geneste klasse erven en wie kan erven. Laten we beginnen met statische geneste klassen.

Statische geneste klassen

Voorbeelden van overerving van geneste klassen - 2Hun erfenisregels zijn de eenvoudigste. Hier kun je bijna alles doen wat je hartje begeert. Een statische geneste klasse kan erven:
  • een gewone klas
  • een statische geneste klasse die wordt gedeclareerd in een buitenste klasse of zijn voorouders
Denk aan een voorbeeld uit onze les over statische geneste 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 static int getMaxPassengersCount() {
          
           return maxPassengersCount;
       }
   }
}
Laten we proberen de code te wijzigen en een Drawingstatische geneste klasse en zijn afstammeling te maken - 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;
       }
   }
}
Zoals je ziet, geen probleem. We kunnen zelfs de klasse eruit halen Drawingen er een gewone openbare klasse van maken in plaats van een statische geneste klasse - er verandert niets.

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;
       }
   }
}
Wij begrijpen dit. Maar welke klassen kunnen een statische geneste klasse erven? Vrijwel elke! Genest/niet-genest, statisch/niet-statisch — het maakt niet uit. Hier laten we de Boeing737Drawinginnerlijke klasse de Drawingstatische geneste klasse erven:

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;
       }
   }
}
U kunt als volgt een instantie maken Boeing737Drawing:

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

   }

}
Hoewel onze Boeing737Drawingklasse een statische klasse erft, is deze zelf niet statisch! Als gevolg hiervan heeft het altijd een instantie van de buitenste klasse nodig. We kunnen de Boeing737Drawingklasse uit de Boeing737klasse verwijderen en er een eenvoudige openbare klasse van maken. Er verandert niets. Het kan nog steeds de Drawingstatische geneste klasse erven.

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;
   
}
Het enige belangrijke punt is dat we in dit geval de statische variabele openbaar moeten maken maxPassengersCount. Als het privé blijft, heeft een gewone openbare klasse er geen toegang toe. We hebben statische lessen bedacht! :) Laten we nu verder gaan met innerlijke klassen. Ze zijn er in 3 soorten: eenvoudige innerlijke klassen, lokale klassen en anonieme innerlijke klassen. Voorbeelden van overerving van geneste klassen - 3Nogmaals, laten we van eenvoudig naar complex gaan :)

Anonieme innerlijke klassen

Een anonieme binnenklasse kan geen andere klasse erven. Geen enkele andere klasse kan een anonieme klasse erven. Simpeler kan het niet! :)

Lokale klassen

Lokale klassen (voor het geval je het vergeten bent) worden gedeclareerd in een codeblok van een andere klasse. Meestal gebeurt dit binnen een of andere methode van de buitenste klasse. Logischerwijs kunnen alleen andere lokale klassen binnen dezelfde methode (of hetzelfde codeblok) een lokale klasse erven. Hier is een voorbeeld:

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
   }
}
Dit is de code van onze les over lokale lessen. Onze nummervalidatieklasse heeft een PhoneNumberlokale klasse. Als we het nodig hebben om twee verschillende entiteiten weer te geven, bijvoorbeeld een mobiel telefoonnummer en een vast telefoonnummer, kunnen we dit alleen binnen dezelfde methode doen. De reden is eenvoudig: het bereik van een lokale klasse is beperkt tot de methode (codeblok) waar deze wordt gedeclareerd. Als gevolg hiervan kunnen we het niet extern gebruiken (ook niet voor klassenovererving). De mogelijkheden voor overerving binnen de lokale klasse zelf zijn echter veel ruimer! Een lokale klasse kan erven:
  1. Een gewone klas.
  2. Een innerlijke klasse die wordt gedeclareerd in dezelfde klasse als de lokale klasse of in een van zijn voorouders.
  3. Een andere lokale klasse gedeclareerd in dezelfde methode (codeblok).
Het eerste en derde punt lijken voor de hand liggend, maar het tweede is een beetje verwarrend :/ Laten we twee voorbeelden bekijken. Voorbeeld 1 — "Een lokale klasse een binnenklasse laten erven die is gedeclareerd in dezelfde klasse als de lokale klasse":

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
   }
}
Hier hebben we de PhoneNumberklasse uit de validatePhoneNumber()methode verwijderd en er een innerlijke klasse van gemaakt in plaats van een lokale klasse. Dit weerhoudt ons er niet van om onze 2 lokale klassen het te laten erven. Voorbeeld 2 - "... of in de voorouders van deze klasse." Dit is al interessanter. We kunnen PhoneNumbernog hoger in de erfenisketen komen. Laten we een abstracte AbstractPhoneNumberValidatorklasse declareren, die de voorouder van onze PhoneNumberValidatorklasse zal worden:

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

}
Zoals je kunt zien, hebben we het niet alleen aangekondigd - we hebben ook de PhoneNumberinnerlijke klasse erin verplaatst. In zijn afstammeling kunnen lokale klassen die in methoden zijn gedeclareerd echter probleemloos PhoneNumberValidatorovererven !PhoneNumber

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
   }
}
Vanwege de overervingsrelatie "zien" de lokale klassen binnen een afstammelingenklasse de innerlijke klassen binnen een voorouder. En tot slot, laten we doorgaan naar de laatste groep :)

Innerlijke klassen

Een innerlijke klasse die is gedeclareerd in dezelfde buitenste klasse (of in zijn afstammeling) kan een andere innerlijke klasse erven. Laten we dit onderzoeken aan de hand van ons voorbeeld met fietsen uit de les over innerlijke klassen.

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
   }
}
Hier hebben we de Seatinnerlijke klasse binnen de Bicycleklasse verklaard. Een speciaal type racestoel, SportSeat, erft het. Maar we zouden een apart type "racefiets" kunnen maken en deze in een aparte klasse kunnen plaatsen:

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!");
       }
   }
}
Dit is ook een optie. De innerlijke klasse van de afstammeling ( SportBicycle.SportSeat) "ziet" de innerlijke klassen van de voorouder en kan deze erven. Het overerven van innerlijke klassen heeft één zeer belangrijke functie! In de vorige twee voorbeelden SportSeatwas onze klas een innerlijke klas. SportSeatMaar wat als we besluiten een gewone openbare klasse te maken die tegelijkertijd de Seatinnerlijke klasse erft?

// 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!");
   }
}
We hebben een fout! Kun je raden waarom? :) Het is allemaal eenvoudig. Toen we het hadden over de Bicycle.Seatbinnenste klasse, vermeldden we dat een verwijzing naar een instantie van de buitenste klasse impliciet wordt doorgegeven aan de constructor van de binnenste klasse. Dit betekent dat u geen object kunt maken Seatzonder een Bicycleobject te maken. Maar hoe zit het met het maken van een SportSeat? In tegenstelling tot Seat, heeft het dit ingebouwde mechanisme niet om de constructor impliciet een verwijzing naar een instantie van de buitenste klasse door te geven. Toch Bicyclekunnen we zonder object geen SportSeatobject maken, net als in het geval van Seat. Daarom rest ons nog maar één ding: expliciet SportSeateen verwijzing naar een object doorgeven aan de constructor Bicycle. Hier is hoe het te doen:

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!");
   }
}
We noemen de superklasse-constructor met super(); Nu, als we een object willen maken SportSeat, zal niets ons ervan weerhouden dit te doen:

public class Main {

   public static void main(String[] args) {

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

   }
}
Opluchting! Deze les was vrij lang :) Maar je hebt veel geleerd! Nu is het tijd om enkele taken op te lossen! :)
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION