JavaRush /Java блогы /Random-KK /Анықтамалық типтердің кеңеюі және қысқаруы

Анықтамалық типтердің кеңеюі және қысқаруы

Топта жарияланған
Сәлеметсіз бе! Алдыңғы лекциялардың бірінде біз қарабайыр типтерді кастинг туралы талқыладық. Біз не туралы айтқанымызды қысқаша еске түсірейік. Анықтамалық түрлердің кеңеюі және қысқаруы - 1Біз қарабайыр типтерді (бұл жағдайда сандық) олар алатын жады көлеміне қарай ұя салатын қуыршақтар ретінде көрсеттік. Естеріңізде болса, кішірек ұя салатын қуыршақты үлкенірекке қою шынайы өмірде де, Java бағдарламалауында да оңай болады.
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
Бұл автоматты түрлендірудің немесе кеңейтудің мысалы . Бұл өздігінен жүреді, сондықтан қосымша code жазудың қажеті жоқ. Ақырында, біз әдеттен тыс ештеңе істеп жатқан жоқпыз: біз жай ғана ұя салатын кішкентай қуыршақты үлкенірек ұя салатын қуыршаққа салып жатырмыз. Керісінше әрекет етіп, үлкен матрешканы кішігірім қуыршаққа салсақ, бұл басқа мәселе. Бұл өмірде мүмкін емес, бірақ бағдарламалауда мұны істеуге болады. Бірақ бір ескерту бар. intЕгер біз айнымалыға мән қоюға тырыссақ short, ол оңай жұмыс істемейді. Өйткені, айнымалыға тек 16 бит ақпарат сыйа алады short, бірақ мән int32 бит алады! Нәтижесінде жіберілген мән бұрмаланады. Компилятор бізге қате береді (« балам, сіз күдікті бірдеңе істеп жатырсыз! »), бірақ егер біз мәнімізді қандай түрге аударатынымызды нақты көрсетсек, ол әлі де осындай әрекетті орындайды.
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Жоғарыдағы мысалда біз дәл осылай жасадық. Операция аяқталды, бірақ shortайнымалыға 32 биттің 16-сы ғана сәйкес болғандықтан, соңғы мән бұрмаланды, нәтижесінде біз -27008 санын алдық . Бұл операция айқын түрлендіру немесе тарылту деп аталады .

Сілтеме түрлерінің ұзаруы мен қысқаруының мысалдары

Енді біз сол операциялар туралы сөйлесетін боламыз, бірақ қарабайыр түрлерге емес, an objectілерге және анықтамалық айнымалыларға қолданылады ! Бұл Java-да қалай жұмыс істейді? Іс жүзінде өте қарапайым. Бір-бірімен байланысы жоқ an objectілер бар. Оларды бір-біріне анық немесе автоматты түрде түрлендіру мүмкін емес деп есептеу қисынды болар еді:
public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

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

   }

}
Бұл жерде біз, әрине, қате аламыз. Сабақтар бір-бірімен байланысты Catемес Dog, біз бірінен екіншісіне «түрлендіргіш» жазбадық. Біз мұны істей алмайтынымыз қисынды: компилятор бұл нысандарды бір-біріне қалай түрлендіру керектігін білмейді. Нысандар бір-бірімен байланысты болса, бұл басқа мәселе! Қалай? Ең алдымен, мұраны пайдалану. Мұрагерлікпен шағын класс жүйесін құруға тырысайық. Бізде жануарларды көрсететін жалпы сынып болады:
public class Animal {

   public void introduce() {

       System.out.println("i'm Animal");
   }
}
Жануарлар, өздеріңіз білетіндей, үй және жабайы:
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");
   }
}
Мысалы, иттерді алайық - үй иті мен қасқыр:
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");
   }
}
Біздің сыныптар оларды қабылдауды жеңілдету үшін әдейі ең қарапайым болып табылады. Бұл жерде бізге өрістер қажет емес және бір әдіс жеткілікті. Келесі codeты іске қосып көрейік:
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Консольге не шығады деп ойлайсыз? introduceСынып Petнемесе сынып әдісі жұмыс істей ме Animal? Оқуды жалғастырмас бұрын жауабыңызды дәлелдеуге тырысыңыз. Міне, нәтиже! Мен үй жануарымын неге жауап осылай болды? Бәрі оңай. Бізде ата-аналық айнымалы және еншілес нысан бар. Жазу арқылы:
Animal animal = new Pet();
Біз сілтеме түрін кеңейттікPet және оның нысанын айнымалыда сақтадық Animal. Қарапайым типтер сияқты, Java-да анықтамалық типтерді кеңейту автоматты түрде орындалады. Бұл үшін қосымша code жазудың қажеті жоқ. Енді бізде ата-аналық сілтемеге тіркелген еншілес нысан бар, нәтижесінде әдіс еншілес сыныпта шақырылғанын көреміз. Бұл codeтың неліктен жұмыс істейтінін әлі толық түсінбесеңіз, оны қарапайым тілде қайта жазыңыз:
Животное животное = new ДомашнееЖивотное();
Бұл жерде проблема жоқ, солай ма? Бұл шынайы өмір деп елестетіп көріңіз, ал бұл жағдайда сілтеме «Жануарлар» деп жазылған қарапайым қағаз белгісі. Егер сіз осындай қағазды алып, оны кез-келген үй жануарының жағасына бекітсеңіз, бәрі жақсы болады. Кез келген үй жануары бәрібір жануар! Кері процесс, яғни мұрагер ағашынан төмен қарай мұрагерлерге көшу тарылту болып табылады:
public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Көріп отырғаныңыздай, мұнда біз an objectімізді қай сыныпқа жібергіміз келетінін нақты көрсетеміз. Бұрын бізде айнымалы болды WildAnimal, ал енді Coyoteол мұра ағашына түседі. Компилятор мұндай операцияны нақты көрсетілімсіз өткізіп жібермейтіні қисынды, бірақ жақшаның ішінде түрін көрсетсеңіз, бәрі жұмыс істейді. Анықтамалық түрлердің кеңеюі және қысқаруы - 2 Басқа, қызықтырақ мысалды қарастырайық:
public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal();//error!
   }
}
Компилятор қате жібереді! Мұның себебі неде? Мәселе мынада, сіз еншілес айнымалыға негізгі нысанды тағайындауға тырысасыз. Басқаша айтқанда, сіз мұны істегіңіз келеді:
ДомашнееЖивотное домашнееЖивотное = new Животное();
Бірақ, мүмкін, егер біз трансляциялауға тырысатын түрді нақты көрсетсек, біз табысқа жете аламыз ба? Сандар жұмыс істейтін сияқты, қолданып көрейік! :)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Java.lang.ClassCastException "main" ағынындағы ерекше жағдай: Жануарды Pet Error файлына шығару мүмкін емес! Компилятор бұл жолы шағымданбады, бірақ нәтижесінде біз ерекшелік алдық. Біз себебін бұрыннан білеміз: біз еншілес айнымалыға негізгі нысанды тағайындауға тырысамыз. Неліктен, шын мәнінде, мұны істеу мүмкін емес? Өйткені барлық жануарлар үй жануарлары емес. Сіз нысанды жасадыңыз Animalжәне оны айнымалыға тағайындауға тырысып жатырсыз Pet. Бірақ, мысалы, көкшіл де Animal, бірақ ол Petүй жануары емес. Басқаша айтқанда, сіз жазған кезде:
Pet pet = (Pet) new Animal();
Онда new Animal()кез келген жануар болуы мүмкін және ол үй болуы міндетті емес! Әрине, сіздің айнымалы Pet petтек үй жануарларын (және олардың ұрпақтарын) сақтауға жарамды және барлығына емес. Сондықтан, мұндай жағдайлар үшін Java-да ерекше ерекшелік жасалды - ClassCastExceptionсыныптарды трансляциялау кезінде қате. Түсінікті болу үшін тағы да айтайық. Негізгі айнымалы (анықтама) ұрпақ класының нысанын көрсете алады:
public class Main {

   public static void main(String[] args) {

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

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Мысалы, бізде бұл жерде ешқандай проблема болмайды. PetБізде сілтеме арқылы көрсетілген нысан бар Pet. Содан кейін жаңа сілтеме сол нысанды көрсете бастады Animal. Осыдан кейін біз түрлендіруді animalжасаймыз Pet. Айтпақшы, біз неге бұлай жасадық? Өткен жолы бізде ерекшелік болды! Өйткені бұл жолы біздің бастапқы нысанымыз Pet pet!
Pet pet =  new Pet();
Ал алдыңғы мысалда бұл an object болды Animal:
Pet pet = (Pet) new Animal();
Тұқымдық айнымалыға тектік нысан тағайындалуы мүмкін емес. Керісінше, сіз мұны істей аласыз.
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION