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.
Biz 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.
Daha maraqlı olan başqa bir nümunəyə baxaq:
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. int
Bir 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 int
32 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 short
32 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 Cat
deyil Dog
və 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? introduce
Sinif Pet
və 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ə Coyote
miras 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](https://cdn.javarush.com/images/article/91ff2c96-bc58-4aa7-a33a-6e1fc0d8969b/1024.jpeg)
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 Animal
və 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 . Pet
Baş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 pet
yalnı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ı - ClassCastException
siniflə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. Pet
Bizdə linklə göstərilən obyekt var Pet
. Sonra eyni obyektə yeni bir keçid göstərməyə başladı Animal
. animal
Bundan 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.
GO TO FULL VERSION