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:
- Adakah kita mewarisi kelas bersarang daripada beberapa kelas atau adakah kita mewarisi kelas lain daripada kelas bersarang?
- Adakah pengganti/diwarisi kelas awam biasa, atau adakah ia juga kelas bersarang?
- Akhir sekali, apakah jenis kelas bersarang yang kita gunakan dalam semua situasi ini?
Kelas bersarang statik
Peraturan 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
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 Drawing
dan 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 Drawing
dan 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 Boeing737Drawing
daripada 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 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());
}
}
Walaupun kelas kami Boeing737Drawing
mewarisi daripada kelas statik, kelas itu sendiri tidak statik! Oleh itu ia akan sentiasa memerlukan contoh kelas luar. Kita boleh mengeluarkan kelas itu Boeing737Drawing
daripada kelas Boeing737
dan 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 maxPassengersCount
awam. 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. Sekali 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:
- Kelas biasa.
- Kelas dalaman yang diisytiharkan dalam kelas yang sama dengan kelas tempatan atau dalam nenek moyangnya.
- Dari kelas tempatan lain yang diisytiharkan dalam kaedah yang sama (blok).
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 PhoneNumber
daripada 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 PhoneNumber
lebih tinggi daripada rantaian warisan. Mari kita isytiharkan kelas abstrak AbstractPhoneNumberValidator
yang 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
}
}
Bicycle
Di 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 SportSeat
mempunyai dalaman. Tetapi bagaimana jika kita memutuskan untuk menjadikannya SportSeat
kelas 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, Bicycle
anda 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 SportSeat
rujukan kepada objek kepada pembina. Bicycle
Begini 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! :)
GO TO FULL VERSION