Salam! Bu gün biz mühüm mexanizmin işinə baxacağıq - yuvalanmış siniflərdə miras. Bilmirəm ki, başqa sinifdən iç-içə sinfi miras almalı olduğunuz zaman nə edəcəyinizi düşünmüsünüzmü. Yoxdursa, inanın: bu vəziyyət çaşdırıcı ola bilər, çünki burada bir çox nüans var:
- Biz hansısa sinifdən iç içə bir sinfi miras alırıq, yoxsa iç içə bir sinifdən başqa bir sinfi miras alırıq?
- Varisi/miras adi ictimai sinifdir, yoxsa o, həm də iç-içə sinifdir?
- Nəhayət, bütün bu vəziyyətlərdə tam olaraq hansı növ iç-içə siniflərdən istifadə edirik?
Statik iç-içə siniflər
Onların varislik qaydaları ən sadədir. Burada ürəyinizin istədiyi hər şeyi edə bilərsiniz. Statik yuvalanmış sinif aşağıdakılardan miras alına bilər:- adi sinif
- xarici sinifdə və ya onun əcdadlarında elan edilən statik yuvalanmış sinif
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;
}
}
}
Drawing
Kodu dəyişdirməyə və statik iç içə sinif və onun nəslini yaratmağa çalışaq - 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;
}
}
}
Gördüyünüz kimi problem yoxdur. Biz sinfi bütövlükdə silə Drawing
və onu statik daxili sinif əvəzinə adi ictimai sinif edə bilərik - heç nə dəyişməyəcək.
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;
}
}
}
Bu sıralanır. Və hansı siniflər statik bir yuvadan miras qala bilər? Demək olar ki, hər hansı! İç içə/müntəzəm, statik/statik olmayan - fərqi yoxdur. Burada biz daxili sinfi Boeing737Drawing
statik yuvalanmış sinifdən miras alırıq 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;
}
}
}
Boeing737Drawing
Belə bir nümunə yarada bilərsiniz:
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());
}
}
Sinifimiz Boeing737Drawing
statik sinifdən miras olsa da, özü statik deyil! Buna görə də həmişə xarici sinif nümunəsinə ehtiyac duyacaq. Biz sinfi Boeing737Drawing
sinifdən çıxarıb Boeing737
onu sadəcə ictimai sinif edə bilərik. Heç nə dəyişməyəcək - o, həmçinin statik yuvadan miras qala bilər 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;
}
Yeganə vacib məqam: bu halda statik dəyişəni ictimai etmək lazımdır maxPassengersCount
. Şəxsi olaraq qalsa, normal ictimai sinifin ona girişi olmayacaq. Statik sinifləri sıraladıq! :) İndi keçək daxili dərslərə. Xatırladığınız kimi, onların 3 növü var: sadəcə olaraq daxili siniflər, yerli siniflər və anonim daxili siniflər. Yenə sadədən mürəkkəbə keçək :)
Anonim daxili siniflər
Anonim daxili sinif başqa sinifdən miras qala bilməz. Heç bir başqa sinif anonim sinifdən varis ola bilməz. Daha sadə ola bilməzdi! :)Yerli siniflər
Yerli siniflər (unutduğunuz halda) başqa bir sinfin kod blokunda elan edilir. Ən tez-tez - bu xarici sinifin bəzi metodu içərisində. Məntiqlidir ki, yalnız eyni metod (və ya blok) daxilində olan digər yerli siniflər yerli sinifdən miras ala bilər. Budur bir nümunə: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 валидации номера
}
}
Bu, yerli siniflər haqqında mühazirəmizin kodudur. Nömrə təsdiqləyici sinifinin içərisində yerli sinifimiz var PhoneNumber
- telefon nömrəsi. Əgər məqsədlərimiz üçün ondan iki ayrı obyekti, məsələn, mobil telefon nömrəsini və stasionar telefon nömrəsini çıxarmaq lazımdırsa, biz bunu yalnız eyni üsulla edə bilərik. Səbəb sadədir: lokal sinfin əhatə dairəsi elan edildiyi metodun (blokun) daxilindədir. Buna görə də biz onu hansısa şəkildə xaricdən istifadə edə bilməyəcəyik (o cümlədən miras üçün). Bununla belə, yerli sinfin özünün miras üçün daha geniş imkanları var! Yerli sinif aşağıdakılardan miras qala bilər:
- Adi sinif.
- Yerli siniflə eyni sinifdə və ya əcdadlarında elan edilən daxili sinif.
- Eyni metodda (blokda) elan edilmiş başqa bir yerli sinifdən.
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 валидации номера
}
}
Burada biz sinfi PhoneNumber
metoddan çıxardıq validatePhoneNumber()
və yerli əvəzinə daxili etdik. Bu, bizim 2 yerli sinifimizi ondan miras almağa mane olmur. Misal 2 – “...yaxud bu sinfin əcdadlarında.” Burada daha maraqlı olur. PhoneNumber
Biz onu miras zəncirində daha da yuxarı qaldıra bilərik . AbstractPhoneNumberValidator
Gəlin bizim əcdadımız olacaq mücərrəd bir sinif elan edək 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;
}
}
}
Gördüyünüz kimi, biz bunu nəinki bəyan etdik, həm də daxili təbəqəni ona köçürdük PhoneNumber
. Bununla belə, onun törəmə sinfində - PhoneNumberValidator
- metodlardakı yerli siniflər 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 валидации номера
}
}
Varislik yolu ilə ünsiyyət sayəsində nəsil sinfi daxilində yerli siniflər əcdadın daxilindəki daxili sinifləri “görür”. Və nəhayət, son qrupa keçək :)
Daxili siniflər
Daxili sinif eyni xarici sinifdə (və ya onun nəslindən) elan edilmiş başqa bir daxili sinif tərəfindən miras qala bilər. Daxili siniflər haqqında mühazirədən velosiped nümunəmizdən istifadə edərək buna baxaq.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
}
}
Burada biz sinif daxilində Bicycle
daxili sinif elan etdik Seat
- oturacaq. Yarış oturacaqlarının xüsusi bir alt növü ondan miras qaldı - SportSeat
. Bununla belə, biz ayrıca bir növ "yarış velosipedi" yarada və onu ayrıca bir sinifə qoya bilərik:
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("Сидение опущено ниже!");
}
}
}
Bu da mümkündür. Uşağın daxili təbəqəsi ( SportBicycle.SportSeat
) əcdadın daxili təbəqələrini “görür” və onlardan miras ala bilər. Daxili siniflərdən miras bir çox vacib xüsusiyyətə malikdir! Əvvəlki iki nümunədə SportSeat
daxili var idi. SportSeat
Bəs onu daxili sinifdən miras qalan müntəzəm ictimai sinif etmək qərarına gəlsək nə olar 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("Сидение опущено ниже!");
}
}
Bizdə xəta var! Bunun nə ilə əlaqəli olduğunu təxmin edə bilərsinizmi? :) Bu sadədir. Daxili sinif haqqında danışarkən Bicycle.Seat
qeyd etdik ki, daxili sinifin konstruktoru xarici sinfin obyektinə istinad edir. Buna görə də, bir obyekt yaratmadan, Bicycle
bir obyekt yarada bilməzsiniz Seat
. Bəs yaradılış SportSeat
? Konstruktorda xarici sinif obyektinə istinadın ötürülməsi üçün eyni daxili mexanizmə malik deyil Seat
. Bununla belə, obyekt olmadan Bicycle
, eynilə ilə olduğu kimi Seat
, obyekt yarada bilmərik SportSeat
. Buna görə də, bizim yalnız bir işimiz qalıb - SportSeat
obyektə istinadı konstruktora Bicycle
açıq şəkildə ötürmək. Bunun necə edildiyi belədir:
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
Bunun üçün xüsusi bir sözdən istifadə edirik super();
. İndi obyekt yaratmaq istəsək SportSeat
, heç nə bizə bunu etməyə mane olmayacaq:
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
Phew, mühazirə olduqca böyük oldu :) Amma siz çox yeni şeylər öyrəndiniz! İndi bir neçə problemi həll etməyin vaxtıdır! :)
GO TO FULL VERSION