CodeGym /Kurslar /Java SELF AZ /Polimorfizm, hissə 3

Polimorfizm, hissə 3

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

1. Tiplərin çevrilməsi

Referans (class) tipli dəyişənləri də müxtəlif tiplərə çevirə bilərik. Amma bu yalnız bir tip iyerarxiyası daxilində işləyir. Gəlin sadə bir nümunə üzərində baxaq. Təsəvvür edək, bizdə belə bir class iyerarxiyası var: aşağıdakı class-lar yuxarıdakı class-dan miras alır.

Tiplərin çevrilməsi

Referans tipli çevirmələr də, primitivlər kimi genişləndirici və daraldıcı olaraq iki yerə bölünür.

Görürük ki, Pişik class-ı EvHeyvanı class-ından miras alıb, və EvHeyvanı class-ı öz növbəsində Heyvan class-ından miras alıb.

Əgər belə bir kod yazsaq:

Heyvan pisik = new Pişik();

Bu tip üçün genişləndirici çevrilmədir: buna bəzən qeyri-aşkar çevrilmə də deyirlər. Biz pisik referansını genişləndirdik və indi o, Pişik tipli obyektə istinad edir. Belə çevrilmədə, pisik referansından istifadə edərək Pişik class-ında olan, amma Heyvan class-ında olmayan metodları çağıra bilmərik.

Daraldıcı çevrilmə (və ya aşkar çevrilmə) isə əksinə baş verir:

Pişik pisike = (Pişik) pisik;

Biz açıq şəkildə göstərmişik ki, pisik dəyişənində saxlanılan referansı (Heyvan tipi) Pişik tipinə çevirmək istəyirik.



2. Obyektin tipinin yoxlanması

Ancaq burada çox diqqətli olmaq lazımdır. Əgər siz belə etsəniz:

Heyvan heyvan = new Pişik();
Canavar bozCanavar = (Canavar) heyvan;

Kompilyator bu kodu keçəcək, amma proqramın icrası zamanı xəta baş verəcək! JVM sizə istisna atacaq:

Exception in thread "main" java.lang.ClassCastException: Pişik cannot be cast to Canavar

Pişik obyekti-nə referansı yalnız Pişik sinifi üçün valideyn siniflərinə — EvHeyvanı, Heyvan və Object tiplərinə aid olan dəyişənlərdə saxlamaq mümkündür.

Niyə belədir?

Məsələ bundadır ki, obyektə referans ondan metodları və dəyişənləri çağırmaq üçün istifadə olunur. Əgər biz Heyvan tipli dəyişəndə Pişik obyekti üçün referans saxlayırıqsa, heç bir problem olmayacaq: Pişik tipində həmişə Heyvan tipində dəyişənlər və metodlar olacaqdır, çünki o, bunları miras alıb!

Amma əgər JVM Pişik obyekti üçün referansı Canavar tipli dəyişəndə saxlamağa icazə versəydi, belə bir vəziyyət yarana bilərdi ki, bozCanavar dəyişənində olmayan bir metod çağırılsın. Buna görə belə saxlama icazə verilmir.

Java-da xüsusi bir operator instanceof var ki, onun vasitəsilə obyektin müəyyən tipdə dəyişəndə saxlanıla bilib-bilməyəcəyini yoxlamaq mümkündür. O, çox sadə görünür:

dəyişən instanceof Tip

Misal:

Heyvan heyvan = new Pişik();
if (heyvan instanceof Canavar)
{
   Canavar bozCanavar = (Canavar) heyvan;
}

Bu kod icra zamanı heç bir xəta yaratmayacaq.

Budur bir neçə başqa misallar və onların izahı:

Tipin genişləndirilməsi Təsvir
Cow cow = new Whale();

Tipin klassik genişləndirilməsi — tip çevrilməsi operatoruna ehtiyac yoxdur. İndi Whale tipli obyekt üçün yalnız Cow sinifində təsvir olunmuş metodları çağırmaq olar.

Kompilyator cow dəyişəni üçün yalnız onun tipi — Cow sinifi tərəfindən təmin edilmiş metodlara icazə verəcək.

Tipin daraldılması
Cow cow = new Whale();
if (cow instanceof Whale) {
   Whale whale = (Whale) cow;
}
Tipin klassik daraldılması: tip yoxlanışı və tip çevrilməsi operatoru əlavə edilməlidir.
cow tipli dəyişən Whale sinifinin obyektinə referans saxlayır.
Biz bunun belə olduğunu yoxlayırıq, və sonra tip çevrilməsi əməliyyatını (daraltma) icra edirik. Və ya buna deyirlər —
type cast
.
Cow cow = new Cow();
Whale whale = (Whale) cow; // exception
Referans tipi daraltmaq üçün obyektin tipini yoxlamadan da əməliyyat edə bilərsiniz.
Lakin, əgər cow dəyişənində Whale sinifinə aid olmayan bir obyekt saxlanıbsa, InvalidClassCastException istisnası yaradılacaq.


3. Orijinal metodu çağırmaq: super

Bəzi hallarda metodu yenidən yazarkən ana sinifin metodunu dəyişdirmək deyil, ona yalnız bir az əlavələr etmək lazım olur.

Əla olardı, əgər metodumuzda ana sinfin eyni metodunu çağıra bilsək və daha sonra öz kodumuzu yaza bilsək. Ya da əvvəlcə öz kodumuzu yazıb, sonra ana sinfin metodunu çağıraq.

Və belə bir imkan Java-da mövcuddur. Məhz ana sinfin metodunu belə çağırırıq:

super.metod(parametrlər);

Nümunələr:

class SülhVahidi
{
   public double getPi()
   {
      return 3.14;
   }
}

class MüharibəVahidi extends SülhVahidi
{
   public double getPi()
   {
      return super.getPi()*2;  // 3.14*2
   }
}

Müharibə vaxtı Pi dəyəri dördə qədər çata bilər, bizim halda isə ümumiyyətlə 6! Əlbəttə, bu zarafatdır, amma bu hər şeyin necə işlədiyini göstərir.

Vəziyyəti bir az aydınlaşdırmaq üçün daha bir neçə nümunə:

Kod Təsvir
class Cow
{
   public void printAll()
   {
      printColor();
      printName();
   }

   public void printColor()
   {
      System.out.println("Mən ağam");
   }

   public void printName()
   {
      System.out.println("Mən inəyəm");
   }
}

class Whale extends Cow
{
   public void printName()
   {
      System.out.print("Bu doğru deyil: ");
      super.printName();
      System.out.println("Mən balinayam");
   }
}
CowWhale sinifləri
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printAll();
}
Ekranda aşağıdakı mətn çıxacaq:
Mən ağam
Bu doğru deyil: Mən inəyəm
Mən balinayam

Bəli, bu asan bir material deyil: açığı desək, bu OOP-da ən çətin mövzularından biridir. Amma bunu bilmək və başa düşmək vacibdir.


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