CodeGym /Kurslar /Java SELF AZ /Başlanğıc İnisializasiyası

Başlanğıc İnisializasiyası

Java SELF AZ
Səviyyə , Dərs
Mövcuddur

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
class Cat
{
   public String name;
   public int age = -1;

   public Cat(String name, int age)
   {
     this.name = name;
     this.age = age;
   }

   public Cat()
   {
     this.name = "Adsız";
   }
}



Ə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
 Cat cat = new Cat("Vaska", 2);
Belə etmək olar: birinci konstruktor çağırılacaq
 Cat cat = new Cat();
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
public class Solution
{
   public int a = b + c + 1;
   public int b = a + c + 2;
   public int c = a + b + 3;
}

Bu kod kompilyasiya olunmayacaq, çünki a dəyişəni yaradılarkən, bc 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
public class Solution
{
   public int a;
   public int b = a + 2;
   public int c = a + b + 3;
}


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.

c dəyişəninə növbə çatanda, ab 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:

class FilePrinter
{
   public String content;

   public FilePrinter(String filename) throws Exception
   {
      FileInputStream input = new FileInputStream(filename);
      byte[] buffer = input.readAllBytes();
      this.content = new String(buffer);
   }

   public void printFile()
   {
      System.out.println(content);
   }
}






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
class Solution
{
   public FilePrinter reader = new FilePrinter("c:\\readme.txt");
}
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
class ParentClass
{    public String a;
   public String b;

   public ParentClass()
   {
   }
}

class ChildClass extends ParentClass
{
   public String c;
   public String d;

   public ChildClass()
   {
   }
}










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

public class Main
{
   public static void main(String[] args)
   {
      ChildClass obj = new ChildClass();
   }

   public static String print(String text)
   {
      System.out.println(text);
      return text;
   }
}

class ParentClass
{
   public String a = Main.print("ParentClass.a");
   public String b = Main.print("ParentClass.b");

   public ParentClass()
   {
      Main.print("ParentClass.constructor");
   }
}

class ChildClass extends ParentClass
{
   public String c = Main.print("ChildClass.c");
   public String d = Main.print("ChildClass.d");

   public ChildClass()
   {
      Main.print("ChildClass.constructor");
   }
}




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 edirik

Mə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 edirik

Mə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ışı
ParentClass.a ParentClass.b ParentClass.constructor
ChildClass.c ChildClass.d ChildClass.constructor

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.


Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION