JavaRush /Blog Java /Random-MS /Warisan kelas bersarang

Warisan kelas bersarang

Diterbitkan dalam kumpulan
hello! Hari ini kita akan melihat operasi mekanisme penting - warisan dalam kelas bersarang. Saya tidak tahu sama ada anda pernah terfikir tentang perkara yang akan anda lakukan apabila anda perlu mewarisi kelas bersarang daripada kelas lain. Jika tidak, percayalah: keadaan ini boleh mengelirukan, kerana terdapat banyak nuansa di sini:
  1. Adakah kita mewarisi kelas bersarang daripada beberapa kelas atau adakah kita mewarisi kelas lain daripada kelas bersarang?
  2. Adakah pengganti/diwarisi kelas awam biasa, atau adakah ia juga kelas bersarang?
  3. Akhir sekali, apakah jenis kelas bersarang yang kita gunakan dalam semua situasi ini?
Jika anda menjawab semua soalan ini, akan ada begitu banyak jawapan yang mungkin sehingga kepala anda akan berputar :) Seperti yang anda tahu, untuk menyelesaikan masalah yang kompleks, anda perlu membahagikannya kepada bahagian yang lebih mudah. Itulah yang akan kita lakukan. Mari kita lihat setiap kumpulan kelas bersarang secara bergilir-gilir dari dua perspektif: siapa yang boleh mewarisi daripada jenis kelas bersarang ini dan daripada siapa kelas itu boleh mewarisi. Mari kita mulakan dengan kelas bersarang statik.

Kelas bersarang statik

Contoh pewarisan kelas dalaman - 2Peraturan pewarisan mereka adalah yang paling mudah. Di sini anda boleh melakukan hampir apa sahaja yang anda inginkan. Kelas bersarang statik boleh diwarisi daripada:
  • kelas biasa
  • kelas bersarang statik yang diisytiharkan dalam kelas luar atau nenek moyangnya
Mari kita ingat contoh dari kuliah tentang kelas bersarang statik.
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;
       }
   }
}
Mari cuba tukar kod dan buat kelas bersarang statik Drawingdan keturunannya - 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;
       }
   }
}
Seperti yang anda lihat, tiada masalah. Kami boleh mengalih keluar kelas itu sama sekali Drawingdan menjadikannya kelas awam biasa dan bukannya kelas bersarang statik - tiada apa yang akan berubah.
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;
       }
   }
}
Itu sudah diselesaikan. Dan kelas apakah yang boleh diwarisi daripada kelas bersarang statik? Hampir semua! Bersarang/biasa, statik/tidak statik - tidak mengapa. Di sini kita mewarisi kelas dalaman Boeing737Drawingdaripada yang bersarang statik 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 Drawing {

   }

   public class Boeing737Drawing extends Drawing {

       public int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Anda boleh membuat contoh Boeing737Drawingseperti ini:
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());

   }

}
Walaupun kelas kami Boeing737Drawingmewarisi daripada kelas statik, kelas itu sendiri tidak statik! Oleh itu ia akan sentiasa memerlukan contoh kelas luar. Kita boleh mengeluarkan kelas itu Boeing737Drawingdaripada kelas Boeing737dan menjadikannya hanya kelas awam. Tiada apa yang akan berubah - ia juga boleh mewarisi daripada bersarang statik Drawing.
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;

}
Satu-satunya perkara penting: dalam kes ini kita perlu membuat pembolehubah statik maxPassengersCountawam. Jika ia kekal peribadi, kelas awam biasa tidak akan mempunyai akses kepadanya. Kami telah menyusun kelas statik! :) Sekarang mari kita beralih ke kelas dalaman. Seperti yang anda ingat, terdapat 3 jenis mereka: hanya kelas dalaman, kelas tempatan dan kelas dalaman tanpa nama. Contoh pewarisan kelas dalaman - 3Sekali lagi, mari kita beralih dari mudah kepada kompleks :)

Kelas dalaman tanpa nama

Kelas dalaman tanpa nama tidak boleh mewarisi daripada kelas lain. Tiada kelas lain boleh mewarisi daripada kelas tanpa nama. Ia tidak boleh menjadi lebih mudah! :)

Kelas tempatan

Kelas tempatan (sekiranya anda terlupa) diisytiharkan di dalam blok kod kelas lain. Selalunya - di dalam beberapa kaedah kelas luar ini. Adalah logik bahawa hanya kelas tempatan lain dalam kaedah (atau blok) yang sama boleh mewarisi daripada kelas tempatan. Berikut ialah contoh:
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 {


       }

       //...code валидации номера
   }
}
Ini adalah kod daripada kuliah kami tentang kelas tempatan. Di dalam kelas pengesah nombor kami mempunyai kelas tempatan PhoneNumber- nombor telefon. Jika untuk tujuan kami, kami perlu memisahkan dua entiti yang berasingan daripadanya, contohnya, nombor telefon mudah alih dan nombor telefon talian tetap, kami hanya boleh melakukan ini dalam kaedah yang sama. Sebabnya mudah: skop kelas tempatan berada dalam kaedah (blok) di mana ia diisytiharkan. Oleh itu, kami tidak akan dapat menggunakannya secara luaran (termasuk untuk warisan). Walau bagaimanapun, kelas tempatan itu sendiri mempunyai kemungkinan yang lebih luas untuk warisan! Kelas tempatan boleh mewarisi daripada:
  1. Kelas biasa.
  2. Kelas dalaman yang diisytiharkan dalam kelas yang sama dengan kelas tempatan atau dalam nenek moyangnya.
  3. Dari kelas tempatan lain yang diisytiharkan dalam kaedah yang sama (blok).
Titik pertama dan ketiga kelihatan jelas, tetapi yang kedua agak mengelirukan :/ Mari kita lihat dua contoh. Contoh 1 - "mewarisi kelas tempatan daripada kelas dalaman yang diisytiharkan dalam kelas yang sama dengan kelas tempatan":
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);
           }
       }

       //...code валидации номера
   }
}
Di sini kami telah mengeluarkan kelas PhoneNumberdaripada kaedah validatePhoneNumber()dan menjadikannya dalaman dan bukannya tempatan. Ini tidak menghalang kami daripada mewarisi 2 kelas tempatan kami daripadanya. Contoh 2 – “...atau dalam nenek moyang kelas ini.” Di sinilah ia menjadi lebih menarik. Kita boleh mengambilnya PhoneNumberlebih tinggi daripada rantaian warisan. Mari kita isytiharkan kelas abstrak AbstractPhoneNumberValidatoryang akan menjadi moyang kita 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;
       }
   }

}
Seperti yang anda lihat, kami bukan sahaja mengisytiharkannya, tetapi juga memindahkan kelas dalaman ke dalamnya PhoneNumber. Walau bagaimanapun, dalam kelas keturunannya - PhoneNumberValidator- kelas tempatan dalam kaedah boleh diwarisi daripada 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);
           }
       }

       //...code валидации номера
   }
}
Terima kasih kepada sambungan melalui warisan, kelas tempatan di dalam kelas keturunan "melihat" kelas dalaman di dalam moyang. Dan akhirnya, mari kita beralih ke kumpulan terakhir :)

Kelas dalaman

Kelas dalam boleh diwarisi oleh kelas dalam lain yang diisytiharkan dalam kelas luar yang sama (atau keturunannya). Mari kita lihat ini menggunakan contoh basikal kami dari kuliah kelas dalaman.
public class Bicycle {

   private String model;
   private int mawWeight;

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

   public void start() {
       System.out.println("Go!");
   }

   class Seat {

       public void up() {

           System.out.println("Сидение поднято выше!");
       }

       public void down() {

           System.out.println("Сидение опущено ниже!");
       }
   }

   class SportSeat extends Seat {

       //...methods
   }
}
BicycleDi sini kami mengisytiharkan kelas dalaman di dalam kelas Seat- tempat duduk. Subjenis khas tempat duduk perlumbaan diwarisi daripadanya - SportSeat. Walau bagaimanapun, kami boleh mencipta jenis "basikal lumba" yang berasingan dan meletakkannya dalam kelas yang berasingan:
public class SportBicycle extends Bicycle {

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


   class SportSeat extends Seat {

       public void up() {

           System.out.println("Сидение поднято выше!");
       }

       public void down() {

           System.out.println("Сидение опущено ниже!");
       }
   }
}
Ini juga mungkin. Kelas dalaman kanak-kanak ( SportBicycle.SportSeat) “melihat” kelas dalaman nenek moyang dan boleh mewarisi daripada mereka. Warisan dari kelas dalaman mempunyai satu ciri yang sangat penting! Dalam dua contoh sebelumnya kami SportSeatmempunyai dalaman. Tetapi bagaimana jika kita memutuskan untuk menjadikannya SportSeatkelas awam biasa, yang juga mewarisi daripada kelas dalaman Seat?
//ошибка! No inclosing instance of  type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

       System.out.println("Сидение поднято выше!");
   }

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
Kami mendapat ralat! Bolehkah anda meneka apa kaitannya? :) Mudah sahaja. Apabila kita bercakap tentang kelas dalam Bicycle.Seat, kita menyebut bahawa pembina kelas dalam secara tersirat memberikan rujukan kepada objek kelas luar. Oleh itu, tanpa mencipta objek, Bicycleanda tidak boleh mencipta objek Seat. Bagaimana dengan penciptaan SportSeat? Ia tidak mempunyai mekanisme terbina dalam yang sama untuk secara tersirat menghantar rujukan kepada objek kelas luar dalam pembina seperti dalam Seat. Walau bagaimanapun, tanpa objek Bicycle, sama seperti dalam kes dengan Seat, kita tidak boleh mencipta objek SportSeat. Oleh itu, kita hanya mempunyai satu perkara yang perlu dilakukan - secara eksplisit memberikan SportSeatrujukan kepada objek kepada pembina. BicycleBegini caranya:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

       System.out.println("Сидение поднято выше!");
   }

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
Untuk ini kami menggunakan perkataan khas super(); Now, jika kami ingin mencipta object SportSeat, tiada apa yang akan menghalang kami daripada melakukan ini:
public class Main {

   public static void main(String[] args) {

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

   }
}
Fuh, kuliah itu ternyata agak besar :) Tetapi anda belajar banyak perkara baru! Sekarang adalah masa untuk menyelesaikan beberapa masalah! :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION