Hai! Hari ini kita akan melihat mekanisme penting: warisan di kelas bersarang. Pernahkah Anda berpikir tentang apa yang akan Anda lakukan jika Anda perlu membuat kelas bersarang mewarisi beberapa kelas lain. Jika tidak, percayalah: situasi ini bisa membingungkan, karena ada banyak nuansa.
Aturan pewarisan mereka adalah yang paling sederhana. Di sini Anda dapat melakukan hampir semua hal yang diinginkan hati Anda. Kelas bersarang statis dapat mewarisi:
Sekali lagi, mari beralih dari yang sederhana ke yang rumit :)
- Apakah kita membuat kelas bersarang mewarisi beberapa kelas? Atau apakah kita membuat beberapa kelas mewarisi kelas bersarang?
- Apakah kelas anak/orang tua adalah kelas publik biasa, atau juga kelas bersarang?
- Terakhir, tipe kelas bersarang apa yang kita gunakan dalam semua situasi ini?
Kelas bersarang statis
![Contoh pewarisan kelas bersarang - 2](https://cdn.codegym.cc/images/article/d85f52e9-8542-4d11-b0f4-5ae516a8ca80/800.jpeg)
- kelas biasa
- kelas bersarang statis yang dideklarasikan di kelas luar atau leluhurnya
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 Drawing
kelas bersarang statis dan 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 bahkan dapat mengeluarkan Drawing
kelas dan menjadikannya kelas publik biasa, bukan kelas bersarang statis — 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;
}
}
}
Kami memahami ini. Tapi kelas apa yang bisa mewarisi kelas bersarang statis? Hampir semua! Bersarang/tidak bersarang, statis/non-statis — tidak masalah. Di sini kita membuat Boeing737Drawing
kelas dalam mewarisi Drawing
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 class Boeing737Drawing extends Drawing {
public int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Anda dapat membuat instance Boeing737Drawing
seperti 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 Boeing737Drawing
kelas kita mewarisi kelas statis, itu sendiri bukanlah kelas statis! Akibatnya, itu akan selalu membutuhkan turunan dari kelas luar. Kita dapat menghapus Boeing737Drawing
kelas dari Boeing737
kelas dan menjadikannya kelas publik yang sederhana. Tidak ada yang berubah. Itu masih bisa mewarisi Drawing
kelas bersarang statis.
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 adalah bahwa dalam hal ini kita perlu membuat maxPassengersCount
variabel statis menjadi publik. Jika tetap privat, maka kelas publik biasa tidak akan memiliki akses ke sana. Kami telah menemukan kelas statis! :) Sekarang mari beralih ke kelas dalam. Mereka datang dalam 3 jenis: kelas dalam sederhana, kelas lokal, dan kelas dalam anonim. ![Contoh pewarisan kelas bersarang - 3](https://cdn.codegym.cc/images/article/10dbf5d7-48f4-4f33-ae56-e2592f9c0037/800.jpeg)
Kelas batin anonim
Kelas dalam anonim tidak dapat mewarisi kelas lain. Tidak ada kelas lain yang dapat mewarisi kelas anonim. Itu tidak bisa lebih sederhana! :)Kelas lokal
Kelas lokal (jika Anda lupa) dideklarasikan di dalam blok kode kelas lain. Paling sering, ini terjadi di dalam beberapa metode kelas luar. Logikanya, hanya kelas lokal lain di dalam metode yang sama (atau blok kode) yang dapat mewarisi kelas lokal. 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 {
}
// ...number validation code
}
}
Ini adalah kode dari pelajaran kita di kelas lokal. Kelas validator nomor kami memiliki PhoneNumber
kelas lokal. Jika kita membutuhkannya untuk mewakili dua entitas berbeda, misalnya, nomor ponsel dan nomor telepon rumah, kita hanya dapat melakukannya dengan metode yang sama. Alasannya sederhana: ruang lingkup kelas lokal terbatas pada metode (blok kode) tempat ia dideklarasikan. Akibatnya, kita tidak akan dapat menggunakannya secara eksternal (termasuk untuk pewarisan kelas). Namun, kemungkinan pewarisan di dalam kelas lokal itu sendiri jauh lebih luas! Kelas lokal dapat mewarisi:
- Kelas biasa.
- Kelas dalam yang dideklarasikan di kelas yang sama dengan kelas lokal atau di salah satu leluhurnya.
- Kelas lokal lain dideklarasikan dengan metode yang sama (blok kode).
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
}
}
Di sini kami menghapus PhoneNumber
kelas dari validatePhoneNumber()
metode dan menjadikannya sebagai kelas dalam, bukan kelas lokal. Ini tidak menghentikan kami untuk membuat 2 kelas lokal kami mewarisinya. Contoh 2 — "... atau nenek moyang kelas ini." Sekarang ini sudah lebih menarik. Kita bisa bergerak PhoneNumber
lebih tinggi lagi dalam rantai warisan. Mari mendeklarasikan AbstractPhoneNumberValidator
kelas abstrak, yang akan menjadi nenek moyang PhoneNumberValidator
kelas kita:
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 — kami juga memindahkan PhoneNumber
inner class ke dalamnya. Namun, dalam turunannya PhoneNumberValidator
, kelas lokal yang dideklarasikan dalam metode dapat mewarisi PhoneNumber
tanpa masalah!
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
}
}
Karena hubungan pewarisan, kelas lokal di dalam kelas turunan "melihat" kelas dalam di dalam leluhur. Dan akhirnya, mari kita lanjutkan ke grup terakhir :)
Kelas batin
Kelas dalam yang dideklarasikan dalam kelas luar yang sama (atau dalam turunannya) dapat mewarisi kelas dalam lainnya. Mari jelajahi ini menggunakan contoh kita dengan sepeda dari pelajaran kelas dalam.
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
}
}
Di sini kami mendeklarasikan Seat
kelas dalam di dalam Bicycle
kelas. Jenis jok balap khusus, SportSeat
mewarisinya. Namun, kita dapat membuat jenis "sepeda balap" terpisah dan meletakkannya di kelas terpisah:
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!");
}
}
}
Ini juga merupakan pilihan. Kelas dalam dari keturunan ( SportBicycle.SportSeat
) "melihat" kelas dalam dari leluhur dan dapat mewarisinya. Mewarisi kelas dalam memiliki satu fitur yang sangat penting! Dalam dua contoh sebelumnya, SportSeat
kelas kita adalah kelas dalam. Tetapi bagaimana jika kita memutuskan untuk membuat SportSeat
kelas publik biasa yang secara bersamaan mewarisi Seat
kelas dalam?
// 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!");
}
}
Kami mendapat kesalahan! Bisakah Anda menebak mengapa? :) Semuanya mudah. Ketika kami berbicara tentang Bicycle.Seat
kelas dalam, kami menyebutkan bahwa referensi ke instance kelas luar secara implisit diteruskan ke konstruktor kelas dalam. Ini berarti Anda tidak dapat membuat Seat
objek tanpa membuat Bicycle
objek. Tapi bagaimana dengan penciptaan SportSeat
? Tidak seperti Seat
, ia tidak memiliki mekanisme bawaan ini untuk secara implisit mengirimkan referensi ke konstruktor ke instance kelas luar. S hingga, tanpa Bicycle
objek, kita tidak dapat membuat SportSeat
objek, seperti dalam kasus Seat
. Oleh karena itu, hanya ada satu hal yang tersisa untuk kita lakukan — secara eksplisit meneruskan SportSeat
referensi ke konstruktor ke suatu Bicycle
objek. Inilah cara melakukannya:
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!");
}
}
Kami memanggil konstruktor superclass menggunakan super();
Now, jika kami ingin membuat SportSeat
objek, tidak ada yang akan menghentikan kami melakukan ini:
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
Fiuh! Pelajaran ini agak panjang :) Tapi Anda belajar banyak! Sekarang saatnya menyelesaikan beberapa tugas! :)
GO TO FULL VERSION