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

Warisan kelas bersarang

Dipublikasikan di grup Random-ID
Halo! Hari ini kita akan melihat pengoperasian mekanisme penting - pewarisan di kelas bersarang. Saya tidak tahu apakah Anda pernah berpikir tentang apa yang akan Anda lakukan ketika Anda perlu mewarisi kelas bersarang dari kelas lain. Jika tidak, percayalah: situasi ini bisa membingungkan, karena ada banyak perbedaan di sini:
  1. Apakah kita mewarisi kelas bertingkat dari suatu kelas ataukah kita mewarisi kelas lain dari kelas bertingkat?
  2. Apakah penerus/yang diwarisi adalah kelas publik biasa, atau juga kelas bersarang?
  3. Terakhir, jenis kelas bersarang apa yang sebenarnya kita gunakan dalam semua situasi ini?
Jika Anda menjawab semua pertanyaan ini, akan ada begitu banyak kemungkinan jawaban yang membuat kepala Anda pusing :) Seperti yang Anda ketahui, untuk menyelesaikan suatu masalah yang kompleks, Anda perlu membaginya menjadi bagian-bagian yang lebih sederhana. Itulah yang akan kami lakukan. Mari kita lihat masing-masing kelompok kelas bersarang dari dua perspektif: siapa yang dapat mewarisi dari jenis kelas bertumpuk ini, dan dari siapa kelas tersebut dapat mewarisi. Mari kita mulai dengan kelas bersarang statis.

Kelas bersarang statis

Contoh pewarisan kelas internal - 2Aturan pewarisan mereka adalah yang paling sederhana. Di sini Anda dapat melakukan hampir semua hal yang diinginkan hati Anda. Kelas bersarang statis dapat diwarisi dari:
  • kelas reguler
  • kelas bersarang statis yang dideklarasikan di kelas luar atau nenek moyangnya
Mari kita ingat contoh dari perkuliahan tentang kelas bersarang statis.
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 kita coba mengubah kode dan membuat kelas bersarang statis Drawingdan turunannya - 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, tidak ada masalah. Kita dapat menghapus seluruh kelas Drawingdan menjadikannya kelas publik biasa, bukan kelas statis yang bersarang - tidak ada 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 beres. Dan kelas apa yang dapat diwarisi dari kelas bersarang statis? Hampir semua! Bersarang/biasa, statis/non-statis - tidak masalah. Di sini kita mewarisi kelas dalam Boeing737Drawingdari kelas statis yang bersarang 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 dapat membuat instance 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());

   }

}
Meskipun kelas kita Boeing737Drawingmewarisi dari kelas statis, kelas itu sendiri tidak statis! Oleh karena itu akan selalu membutuhkan sebuah instance dari kelas luar. Kita dapat mengeluarkan kelas tersebut Boeing737Drawingdari kelas tersebut Boeing737dan menjadikannya hanya kelas publik. Tidak ada yang akan berubah - ini juga dapat mewarisi dari file 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 poin penting: dalam hal ini kita perlu membuat variabel statis menjadi maxPassengersCountpublik. Jika tetap privat, kelas publik normal tidak akan memiliki akses ke sana. Kami telah memilah kelas statis! :) Sekarang mari kita beralih ke kelas dalam. Seperti yang Anda ingat, ada 3 jenisnya: kelas dalam saja, kelas lokal, dan kelas dalam anonim. Contoh pewarisan kelas internal - 3Sekali lagi, mari beralih dari yang sederhana ke yang rumit :)

Kelas dalam anonim

Kelas dalam anonim tidak dapat mewarisi kelas lain. Tidak ada kelas lain yang dapat mewarisi kelas anonim. Ini sangat sederhana! :)

Kelas lokal

Kelas lokal (jika Anda lupa) dideklarasikan di dalam blok kode kelas lain. Paling sering - di dalam beberapa metode kelas luar ini. Adalah logis bahwa hanya kelas lokal lain dalam metode (atau blok) yang sama yang dapat mewarisi kelas lokal. Berikut ini contohnya:
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 kode dari kuliah kita tentang kelas lokal. Di dalam kelas validator nomor kami memiliki kelas lokal PhoneNumber- nomor telepon. Jika untuk tujuan kita perlu mengekstrak dua entitas terpisah darinya, misalnya nomor ponsel dan nomor telepon rumah, kita hanya dapat melakukannya dengan metode yang sama. Alasannya sederhana: ruang lingkup kelas lokal berada dalam metode (blok) di mana ia dideklarasikan. Oleh karena itu, kami tidak akan dapat menggunakannya secara eksternal (termasuk untuk warisan). Namun, kelas lokal sendiri memiliki kemungkinan pewarisan yang lebih luas! Kelas lokal dapat mewarisi dari:
  1. Kelas reguler.
  2. Kelas dalam yang dideklarasikan di kelas yang sama dengan kelas lokal atau di kelas leluhurnya.
  3. Dari kelas lokal lain yang dideklarasikan dengan metode (blok) yang sama.
Poin pertama dan ketiga terlihat jelas, namun poin kedua agak membingungkan :/ Mari kita lihat dua contoh. Contoh 1 - “mewarisi kelas lokal dari kelas dalam yang dideklarasikan di kelas yang sama dengan kelas lokal”:
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 kita telah mengeluarkan kelas PhoneNumberdari metode validatePhoneNumber()dan menjadikannya internal, bukan lokal. Ini tidak menghalangi kita untuk mewarisi 2 kelas lokal kita darinya. Contoh 2 – “...atau nenek moyang kelas ini.” Di sinilah hal menjadi lebih menarik. Kita bisa membawanya PhoneNumberlebih tinggi lagi dalam rantai warisan. Mari kita mendeklarasikan kelas abstrak AbstractPhoneNumberValidatoryang akan menjadi nenek 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 tidak hanya mendeklarasikannya, tetapi juga memindahkan kelas dalam ke dalamnya PhoneNumber. Namun, di kelas turunannya - PhoneNumberValidator- kelas lokal dalam metode dapat diwarisi dari 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 валидации номера
   }
}
Berkat koneksi melalui pewarisan, kelas lokal di dalam kelas turunan “melihat” kelas dalam di dalam leluhurnya. Dan terakhir, mari kita beralih ke grup terakhir :)

Kelas dalam

Kelas dalam dapat diwarisi oleh kelas dalam lain yang dideklarasikan di kelas luar yang sama (atau turunannya). Mari kita lihat ini dengan menggunakan contoh sepeda dari kuliah di kelas dalam.
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 mendeklarasikan kelas internal di dalam kelas Seat- kursi. Subtipe khusus kursi balap diwarisi darinya - SportSeat. Namun, kita dapat membuat jenis "sepeda balap" terpisah dan memasukkannya ke dalam kelas terpisah:
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("Сидение опущено ниже!");
       }
   }
}
Hal ini juga mungkin terjadi. Kelas dalam anak ( SportBicycle.SportSeat) “melihat” kelas dalam leluhur dan dapat mewarisinya. Warisan dari kelas dalam memiliki satu ciri yang sangat penting! Dalam dua contoh sebelumnya kita SportSeatmempunyai internal. Namun bagaimana jika kita memutuskan untuk menjadikannya SportSeatkelas publik biasa, yang juga mewarisi kelas dalam 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 kesalahan! Bisakah Anda menebak apa hubungannya? :) Itu mudah. Ketika kita berbicara tentang kelas dalam Bicycle.Seat, kita menyebutkan bahwa konstruktor kelas dalam secara implisit meneruskan referensi ke objek kelas luar. Oleh karena itu, tanpa membuat objek, BicycleAnda tidak dapat membuat objek Seat. Bagaimana dengan penciptaan SportSeat? Ia tidak memiliki mekanisme bawaan yang sama untuk secara implisit meneruskan referensi ke objek kelas luar di konstruktor seperti pada Seat. Namun, tanpa objek Bicycle, seperti halnya dengan Seat, kita tidak dapat membuat objek SportSeat. Oleh karena itu, kita hanya memiliki satu hal yang harus dilakukan - secara eksplisit meneruskan SportSeatreferensi ke objek ke konstruktor. BicycleBegini cara melakukannya:
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 kita menggunakan kata khusus. super(); Sekarang, jika kita ingin membuat sebuah objek SportSeat, tidak ada yang akan menghentikan kita melakukan ini:
public class Main {

   public static void main(String[] args) {

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

   }
}
Fiuh, kuliahnya ternyata lumayan besar :) Tapi kamu belajar banyak hal baru! Sekaranglah waktunya untuk menyelesaikan beberapa masalah! :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION