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:
- Apakah kita mewarisi kelas bertingkat dari suatu kelas ataukah kita mewarisi kelas lain dari kelas bertingkat?
- Apakah penerus/yang diwarisi adalah kelas publik biasa, atau juga kelas bersarang?
- Terakhir, jenis kelas bersarang apa yang sebenarnya kita gunakan dalam semua situasi ini?
Kelas bersarang statis
Aturan 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
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 Drawing
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 dapat menghapus seluruh kelas Drawing
dan 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 Boeing737Drawing
dari 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 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 kelas kita Boeing737Drawing
mewarisi dari kelas statis, kelas itu sendiri tidak statis! Oleh karena itu akan selalu membutuhkan sebuah instance dari kelas luar. Kita dapat mengeluarkan kelas tersebut Boeing737Drawing
dari kelas tersebut Boeing737
dan 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 maxPassengersCount
publik. 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. Sekali 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:
- Kelas reguler.
- Kelas dalam yang dideklarasikan di kelas yang sama dengan kelas lokal atau di kelas leluhurnya.
- Dari kelas lokal lain yang dideklarasikan dengan metode (blok) yang sama.
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 PhoneNumber
dari 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 PhoneNumber
lebih tinggi lagi dalam rantai warisan. Mari kita mendeklarasikan kelas abstrak AbstractPhoneNumberValidator
yang 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
}
}
Bicycle
Di 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 SportSeat
mempunyai internal. Namun bagaimana jika kita memutuskan untuk menjadikannya SportSeat
kelas 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, Bicycle
Anda 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 SportSeat
referensi ke objek ke konstruktor. Bicycle
Begini 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! :)
GO TO FULL VERSION