JavaRush /Java Blogu /Random-AZ /İstinad növlərinin genişlənməsi və daralması

İstinad növlərinin genişlənməsi və daralması

Qrupda dərc edilmişdir
Salam! Əvvəlki mühazirələrdən birində biz ibtidai tiplərin dökümünü müzakirə etdik. Nə haqqında danışdığımızı qısaca xatırlayaq. İstinad növlərinin genişlənməsi və daralması - 1Biz primitiv tipləri (bu halda rəqəmli) tutduqları yaddaşın həcminə görə yuva kuklaları kimi təqdim etdik. Xatırladığınız kimi, daha kiçik yuva kuklasını daha böyük birinə yerləşdirmək həm real həyatda, həm də Java proqramlaşdırmasında sadə olacaq.
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
Bu, avtomatik çevrilmə və ya genişləndirmə nümunəsidir . Bu, öz-özünə baş verir, ona görə də əlavə kod yazmağa ehtiyac yoxdur. Sonda biz qeyri-adi heç nə etmirik: sadəcə olaraq daha kiçik yuva kuklasını daha böyük yuva kuklasına qoyuruq. Əksini etməyə çalışsaq və böyük bir matryoshka kuklasını daha kiçikə qoysaq, başqa bir məsələdir. Bunu həyatda etmək olmaz, amma proqramlaşdırmada bunu etmək olar. Ancaq bir xəbərdarlıq var. intBir dəyişənə dəyər qoymağa çalışsaq short, o qədər də asan alınmayacaq. Axı, bir dəyişənə yalnız 16 bit məlumat sığa bilər short, lakin dəyər int32 bit alır! Nəticədə ötürülən dəyər təhrif olunacaq. Kompilyator bizə xəta verəcək (“ dostum, sən şübhəli bir şey edirsən! ”), lakin dəyərimizi hansı tipə köçürəcəyimizi açıq şəkildə göstərsək, o, yenə də belə bir əməliyyat həyata keçirəcək.
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Yuxarıdakı nümunədə biz bunu etdik. Əməliyyat tamamlandı, lakin short32 bitdən yalnız 16-sı dəyişənə uyğun gəldiyi üçün son qiymət təhrif edildi və nəticədə -27008 nömrəsini aldıq . Bu əməliyyat açıq konversiya və ya daraltma adlanır .

İstinad növlərinin uzadılması və daralması nümunələri

İndi eyni əməliyyatlar haqqında danışacağıq, lakin ibtidai növlərə deyil, obyektlərə və istinad dəyişənlərinə aiddir ! Bu Java-da necə işləyir? Əslində olduqca sadə. Bir-biri ilə əlaqəsi olmayan obyektlər var. Onların nə açıq, nə də avtomatik olaraq bir-birinə çevrilə bilməyəcəyini düşünmək məntiqli olardı:
public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog();//error!

   }

}
Burada, əlbəttə ki, bir səhv alacağıq. Dərslər bir-biri ilə əlaqəli Catdeyil Dogvə biz birindən digərinə “çevirici” yazmamışıq. Məntiqlidir ki, biz bunu edə bilməyəcəyik: tərtibçinin bu obyektləri bir-birinə necə çevirmək barədə heç bir fikri yoxdur. Obyektlərin bir-birinə bağlı olması başqa məsələdir! Necə? İlk növbədə, mirasdan istifadə etməklə. Gəlin mirasla kiçik bir sinif sistemi yaratmağa çalışaq. Heyvanları təmsil edən ümumi sinifimiz olacaq:
public class Animal {

   public void introduce() {

       System.out.println("i'm Animal");
   }
}
Heyvanlar, bildiyiniz kimi, ev və vəhşidir:
public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("i'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("i'm Pet");
   }
}
Məsələn, itləri götürək - ev iti və koyot:
public class Dog extends Pet {

   public void introduce() {

       System.out.println("i'm Dog");
   }
}





public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println("i'm Coyote");
   }
}
Dərslərimiz onların qavranılmasını asanlaşdırmaq üçün bilərəkdən ən primitivdir. Burada həqiqətən sahələrə ehtiyacımız yoxdur və bir üsul kifayətdir. Aşağıdakı kodu işlətməyə çalışaq:
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Sizcə konsola nə çıxacaq? introduceSinif Petvə ya sinif metodu işləyəcəkmi Animal? Oxumağa davam etməzdən əvvəl cavabınızı əsaslandırmağa çalışın. Və nəticə budur! mən Petəm cavab niyə belə oldu? Bu sadədir. Bizim valideyn dəyişənimiz və uşaq obyektimiz var. Yazmaqla:
Animal animal = new Pet();
Biz istinad tipini genişləndirdikPet və onun obyektini dəyişəndə ​​saxladıq Animal. İbtidai növlərdə olduğu kimi, Java-da istinad növlərinin genişləndirilməsi avtomatik həyata keçirilir. Bunun üçün əlavə kod yazmağa ehtiyac yoxdur. İndi ana istinada əlavə edilmiş uşaq obyektimiz var və nəticədə metodun uşaq sinifdə çağırıldığını görürük. Bu kodun niyə işlədiyini hələ də tam başa düşmürsünüzsə, onu sadə dildə yenidən yazın:
Животное животное = new ДомашнееЖивотное();
Bununla heç bir problem yoxdur, elə deyilmi? Təsəvvür edin ki, bu real həyatdır və bu halda link “Heyvan” deyən sadə kağız etiketidir. Belə bir kağız parçası götürsəniz və hər hansı bir ev heyvanının yaxasına yapışdırsanız, hər şey yaxşı olacaq. Hər hansı bir ev heyvanı hələ də bir heyvandır! Əks proses, yəni miras ağacından varislərə doğru hərəkət daralmadır:
public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Gördüyünüz kimi, burada obyektimizi hansı sinfə köçürmək istədiyimizi açıq şəkildə göstəririk. Əvvəllər bizdə dəyişən var idi WildAnimal, indi isə Coyotemiras ağacına enir. Məntiqlidir ki, kompilyator belə bir əməliyyatı açıq bir işarə olmadan atlamayacaq, ancaq mötərizədə növü göstərsəniz, hər şey işləyəcək. İstinad növlərinin genişlənməsi və daralması - 2 Daha maraqlı olan başqa bir nümunəyə baxaq:
public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal();//error!
   }
}
Kompilyator xəta verir! Səbəb nədir? Fakt budur ki, siz uşaq dəyişənə ana obyekt təyin etməyə çalışırsınız. Başqa sözlə, bunu etmək istəyirsiniz:
ДомашнееЖивотное домашнееЖивотное = new Животное();
Bəs, bəlkə, yayımlamağa çalışdığımız tipi açıq şəkildə göstərsək, uğur qazanarıq? Rəqəmlər işləyir, gəlin cəhd edək! :)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
"Əsas" mövzuda istisna java.lang.ClassCastException: Heyvan Pet Xətasına ötürülə bilməz ! Tərtibatçı bu dəfə şikayət etmədi, amma nəticədə istisna aldıq. Səbəbini artıq bilirik: biz uşaq dəyişənə ana obyekt təyin etməyə çalışırıq. Niyə, əslində, bunu etmək mümkün deyil? Çünki bütün Heyvanlar Ev heyvanı deyil. Siz obyekt yaratdınız Animalvə onu dəyişənə təyin etməyə çalışırsınız Pet. Amma, məsələn, koyot da ev heyvanıdır Animal, amma o deyil . PetBaşqa sözlə, yazdığınız zaman:
Pet pet = (Pet) new Animal();
Orada new Animal()hər hansı bir heyvan ola bilər və onun ev heyvanı olması lazım deyil! Təbii ki, dəyişəniniz Pet petyalnız ev heyvanlarını (və onların nəsillərini) saxlamaq üçün uyğundur, hər kəs üçün deyil. Buna görə də, bu cür hallar üçün Java-da xüsusi bir istisna yaradıldı - ClassCastExceptionsiniflərin ötürülməsi zamanı səhv. Daha aydın olması üçün bir daha deyək. Ana dəyişən (istinad) nəsil sinfinin obyektinə işarə edə bilər:
public class Main {

   public static void main(String[] args) {

       Pet pet =  new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Məsələn, burada heç bir problemimiz olmayacaq. PetBizdə linklə göstərilən obyekt var Pet. Sonra eyni obyektə yeni bir keçid göstərməyə başladı Animal. animalBundan sonra çevirməni edirik Pet. Yeri gəlmişkən, biz bunu niyə etdik? Keçən dəfə bir istisnamız oldu! Çünki bu dəfə bizim orijinal obyektimiz Pet pet!
Pet pet =  new Pet();
Əvvəlki nümunədə bu bir obyekt idi Animal:
Pet pet = (Pet) new Animal();
Nəsil dəyişənə əcdad obyekti təyin edilə bilməz. Əksinə, bunu edə bilərsiniz.
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION