1. Əvəzlənlərin initializasiyası
Bildiyiniz kimi, sinfinizdə bir neçə əvəzlən elan etmək olar və sadəcə elan etmək yox, həm də onları başlanğıc dəyərlərlə initializasiya etmək olar.
Amma bu əvəzlənləri konstruktor vasitəsilə də initializasiya etmək mümkündür. Bu səbəbdən nəzəri olaraq, belə bir vəziyyət yarana bilər ki, sinfin əvəzlənlərinin dəyərləri iki dəfə təyin edilir. Məsələn:
Kod | Qeyd |
---|---|
|
Əvəzlənə age başlanğıc dəyər təyin edilir Başlanğıc dəyər dəyişdirilir age üçün başlanğıc dəyər istifadə olunur |
|
Belə etmək olar: birinci konstruktor çağırılacaq |
|
Belə etmək olar: ikinci konstruktor çağırılacaq |
Kod Cat cat = new Cat("Vaska", 2);
icra edilərkən belə hadisələr baş verəcək:
Cat
tipində obyekt yaradılır- Bütün sinif əvəzlənləri başlanğıc dəyərlərlə initializasiya edilir
- Konstruktor çağırılır və onun kodu icra edilir.
Yəni, sinif əvəzlənləri əvvəlcə başlanğıc dəyərlərlə initializasiya edilir, sonra isə konstruktorun kodu icra olunur.
2. Sinif dəyişənlərinin initializasiya sırası
Dəyişənlər konstruktor başlamazdan əvvəl yalnız initializasiya edilmir: onlar həmçinin sinifdəki elan olunma sırasına görə müəyyən edilmiş şəkildə initializasiya edilirlər.
Gəlin bu maraqlı koda baxaq:
Kod | Qeyd |
---|---|
|
Bu kod kompilyasiya olunmayacaq, çünki a
dəyişəni yaradılarkən, b
və c
dəyişənləri hələ mövcud deyil. Amma bu şəkildə yaza bilərsiniz və bu kod çox gözəl kompilyasiya olunacaq və işləyəcək.
Kod | Qeyd |
---|---|
|
0 0+2 0+2+3 |
Qeyd: Amma yadınızda saxlayın ki, kodunuz digər proqramçılar üçün şəffaf olmalıdır, belə ki, bu kimi yanaşmaların istifadəsindən çəkinin — bu kodun oxunmasını çətinləşdirir.
Bunu yadda saxlamalısınız ki, bütün sinif dəyişənləri onlar üçün hansısa bir dəyər təyin edilmədən əvvəl default dəyər alır. int
tipi üçün bu, sıfırdır.
JVM a
dəyişənini initializasiya edərkən, sadəcə olaraq, ona int tipinin default dəyərini — 0-ı təyin edəcək.
b
növbəsinə çatanda, a dəyişəni artıq məlum olacaq və bir dəyər saxlayacaq, buna görə də JVM ona 2 dəyərini təyin edəcək.
Və c
dəyişəninə növbə çatanda, a
və b
dəyişənləri artıq initializasiya olunmuş olacaq və JVM asanlıqla c
üçün başlanğıc dəyəri hesablayacaq: 0+2+3.
Əgər bir dəyişəni metod daxilində yaradarsınızsa, ona hansısa bir dəyər təyin etmədən onu istifadə edə bilməzsiniz. Amma sinif dəyişənləri ilə bu belə deyil. Əgər sinif dəyişəninə başlanğıc dəyər təyin edilməyibsə, o zaman ona default dəyər təyin olunur.
3. Sabitlər
Obyekt yaratma prosesini müzakirə etməyə davam etdiyimizə görə, sinif dəyişənləri olan və final
modifikatoruna sahib olan sabitlərin inizializasiyası məsələsinə də toxunmaq lazımdır.
Əgər sinif dəyişəni final
modifikatoruna malikdirsə, ona başlanğıc dəyər təyin edilməlidir. Bunu artıq bilirsiniz və bu, təəccüblü bir şey deyil.
Ancaq bilmədiyiniz odur ki, başlanğıc dəyər dərhal təyin edilməyə bilər, əgər bu dəyər konstruktorda təyin edilərsə. Bu, final-dəyişən üçün mükəmməl işləyəcək. Yeganə tələb — əgər bir neçə konstruktor varsa, final dəyişənə bütün konstruktorlarda dəyər təyin edilməlidir.
Nümunə:
public class Cat
{
public final int maxAge = 25;
public final int maxWeight;
public Cat (int weight)
{
this.maxWeight = weight; // sabitə başlanğıc dəyəri təyin olunur
}
}
4. Konstruktor içində kod
Konstruktorlar haqqında daha bir neçə vacib qeyd var. Gələcəkdə Java öyrənərkən irslənmə, seriyalaşdırma, istisnalar və s. kimi məsələlərlə qarşılaşacaqsınız. Onlar hamısı müxtəlif dərəcədə konstruktorların işinə təsir edir. İndi bu mövzulara həddən artıq dərindən getməyə ehtiyac yoxdur, amma ən azından onları qısaca müzakirə etməyə borcluyuq.
Məsələn, konstruktorlarla bağlı bir vacib qeyd. Nəzəri olaraq, konstruktorda istənilən dərəcədə mürəkkəb kod yazmaq olar. Amma bunu etmək lazım deyil. Məsələn:
|
Fayl oxuma axını açırıq Faylı byte massivi kimi oxuyuruq Byte massivini string kimi saxlayırıq Faylın məzmununu ekrana çıxarırıq |
FilePrinter klassının konstruktorunda biz birbaşa fayla byte axını açmışıq və onun məzmununu oxumuşuq. Bu olduqca mürəkkəb davranışdır və potensial olaraq xətalara səbəb ola bilər.
Bəs belə bir fayl yoxdursa? Yaxud onun oxunmasında problem yaranarsa? Ya da fayl çox böyükdürsə?
Mürəkkəb məntiq xətalara daha çox ehtimallar və düzgün istisna işlənməsi tələb edən kod anlamına gəlir.
Nümunə 1 – Seriyalaşdırma
Adi Java proqramında çox vəziyyətlər var ki, sizin klassınızın obyektləri sizin tərəfinizdən yaradılmır. Məsələn, obyektinizi şəbəkə üzərindən ötürmək qərarına gəlirsiniz: bu halda Java maşını obyektinizi byte dəsti şəklinə çevirir, ötürür və yenidən byte dəstləri əsasında obyekt yaradır.
Və belə anlaşılıb ki, digər kompüterdə sizin faylınız yoxdur, konstruktorda xəta yaranır və heç kim onu həll etmir — bu isə proqramın bağlanmasına səbəb ola bilər.
Nümunə 2 — Klass sahələrinin initializasiyası
Klassınızın konstruktoru checked-istisnalar ata bilərsə – throws açar sözü var – siz bu istisnanı obyektinizi yaradan metodda tutmağa məcbursunuz.
Yox əgər belə bir metod yoxdursa? Məsələn:
Kod | Qeyd |
---|---|
|
Bu kod kompilyasiya olunmayacaq. |
FilePrinter
klassının konstruktoru checked-istisnalar ehtiva edir: siz FilePrinter
obyektini try-catch daxilində yazmadan yarada bilməzsiniz. Amma try-catch yalnız metod daxilində yazıla bilər.
5. Əsas sinifin konstruktoru
Əvvəlki dərslərdə bir az irsiyyətdən danışmışdıq. Təəssüf ki, irsiyyət və OOP-nu tam müzakirə etməyəcəyik, bu mövzulara yalnız OOP hissəsində toxunacağıq. Amma bu konstruktora aiddir.
Əgər sinfinizi başqa bir sinifdən irs alsanız, sinfinizin obyektinə faktiki olaraq valideyn sinifin obyekti daxildir. Üstəlik, bu valideyn sinfinin öz class dəyişənləri və konstrukturları var.
Ona görə də sizin üçün vacibdir başa düşmək ki, parametrlərin initializasiyası və konstruktorların çağırışı necə baş verir, əgər sizin sinfinizin bir valideyn sinfi varsa, onun dəyişənlərini və metodlarını irs alırsınız.
Siniflər
Dəyişənlərin hansı ardıcıllıqla initializə olduğunu və konstruktorların hansı ardıcıllıqla çağırıldığını necə öyrənəcəyik? Gəlin əvvəlcə iki sinifin kodunu yazaq, biri o birindən irs alır:
Kod | Qeyd |
---|---|
|
Sinif ChildClass sinifindən irs alır ParentClass. |
Dəyişənlərin hansı ardıcıllıqla initializə edildiyini və konstruktorların hansı ardıcıllıqla çağırıldığını müəyyən etməliyik. Bunu loglama vasitəsilə müəyyən edə bilərik.
Loglama
Loglama - proqramın iş prosesi zamanı baş verən hadisələrin konsola və ya fayla yazılmasıdır.
Konstruktora çağırıldığını müəyyən etmək çox asandır: konstruktorun daxilində bu barədə konsola mesaj yazmaq lazımdır. Amma dəyişənin initializasiya edildiyini necə müəyyən etmək olar?
Əslində bu da çox çətin deyil: sinfin dəyişənini initializasiya etmək üçün istifadə edilən dəyəri qaytaran xüsusi bir metod yazmalıyıq və bu faktı loqlamalıyıq. Kod belə görünə bilər:
Son kod
|
ChildClass növündə obyekt yaradırıq Bu metod konsola ötürülən mətn yazır və onu qaytarır ParentClass elan edirikMətni yazırıq və onunla dəyişənləri initializasiya edirik Konstruktor çağırışı haqqında mesajı konsola yazırıq. Döndürülən mənanı nəzərə almırıq. ChildClass elan edirikMətni yazırıq və onunla dəyişənləri initializasiya edirik Konstruktor çağırışı haqqında mesajı konsola yazırıq. Döndürülən mənanı nəzərə almırıq. |
Bu kodu işlədəndə ekrana belə bir mətn çıxacaq:
Main.print() metodunun ekran çıxışı |
---|
|
Beləliklə, siz həmişə şəxsən əmin ola bilərsiniz ki, sinifin dəyişənləri konstruktor çağırışından əvvəl initializasiya olunur. Əsas sinfin bütün initializasiyası sinif-in-irs alıcısından əvvəl gedir.
GO TO FULL VERSION