JavaRush /وبلاگ جاوا /Random-FA /انبساط و انقباض انواع مرجع

انبساط و انقباض انواع مرجع

در گروه منتشر شد
سلام! در یکی از سخنرانی های قبلی، در مورد ریخته گری انواع اولیه بحث کردیم. بیایید به طور خلاصه به یاد بیاوریم که در مورد چه چیزی صحبت می کردیم. انبساط و انقباض انواع مرجع - 1ما انواع اولیه (در این مورد عددی) را به عنوان عروسک های تودرتو با توجه به میزان حافظه ای که آنها اشغال می کنند نشان دادیم. همانطور که به یاد دارید، قرار دادن یک عروسک تودرتوی کوچکتر در یک عروسک بزرگتر هم در زندگی واقعی و هم در برنامه نویسی جاوا ساده خواهد بود.
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
این نمونه ای از تبدیل خودکار یا پسوند است . این به خودی خود اتفاق می افتد، بنابراین نیازی به نوشتن کد اضافی نیست. در پایان، ما هیچ کار غیرعادی انجام نمی دهیم: ما به سادگی یک عروسک تودرتو کوچکتر را در یک عروسک لانه ساز بزرگتر قرار می دهیم. اگر سعی کنیم برعکس عمل کنیم و یک عروسک ماتریوشکای بزرگ را در یک عروسک کوچکتر قرار دهیم، موضوع دیگری است. این را نمی توان در زندگی انجام داد، اما در برنامه نویسی می توان آن را انجام داد. اما یک اخطار وجود دارد. اگر بخواهیم مقداری را 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تنها 16 بیت از 32 بیت در متغیر قرار می‌گیرد، مقدار نهایی مخدوش شد و در نتیجه عدد -27008 را دریافت کردیم . این عملیات تبدیل صریح یا باریک کردن نامیده می شود .

نمونه هایی از گسترش و انقباض انواع مرجع

اکنون در مورد همان عملیات صحبت خواهیم کرد، اما نه برای انواع اولیه، بلکه برای اشیاء و متغیرهای مرجع ! این چگونه در جاوا کار می کند؟ در واقع بسیار ساده است. اشیایی وجود دارند که به یکدیگر مرتبط نیستند. منطقی است که فرض کنیم آنها را نمی توان به طور صریح یا خودکار به یکدیگر تبدیل کرد:
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");
   }
}
کلاس‌های ما عمدا ابتدایی‌ترین کلاس‌ها هستند تا درک آن‌ها آسان‌تر شود. ما در اینجا واقعاً به فیلد نیاز نداریم و یک روش کافی است. بیایید سعی کنیم کد زیر را اجرا کنیم:
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
به نظر شما خروجی کنسول چه خواهد بود؟ آیا روش introduceکلاس Petیا کلاس کار می کند Animal؟ سعی کنید قبل از ادامه خواندن پاسخ خود را توجیه کنید. و این هم از نتیجه! من حیوان خانگی هستم چرا جواب اینگونه شد؟ ساده است. ما یک متغیر والد و یک شی فرزند داریم. با نوشتن:
Animal animal = new Pet();
ما یک نوع مرجع را گسترش دادهPet ایم و شی آن را در یک متغیر ذخیره کرده ایم Animal. همانند انواع اولیه، گسترش انواع مرجع در جاوا به صورت خودکار انجام می شود. برای این کار نیازی به نوشتن کد اضافی نیست. اکنون یک شی فرزند داریم که به مرجع والد متصل است و در نتیجه می بینیم که متد در کلاس فرزند فراخوانی می شود. اگر هنوز به طور کامل نمی‌دانید چرا این کد کار می‌کند، آن را به زبان ساده بازنویسی کنید:
Животное животное = new ДомашнееЖивотное();
هیچ مشکلی با آن وجود ندارد، درست است؟ تصور کنید این زندگی واقعی است، و پیوند در این مورد یک برچسب کاغذی ساده است که روی آن نوشته شده است "حیوان". اگر چنین تکه کاغذی را بردارید و آن را به یقه هر حیوان خانگی بچسبانید، همه چیز خوب می شود. هر حیوان خانگی هنوز یک حیوان است! روند معکوس، یعنی انتقال درخت ارث به سمت وارثان، باریک شدن است:
public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
همانطور که می بینید، در اینجا به صراحت نشان می دهیم که می خواهیم شی خود را به کدام کلاس ارسال کنیم. قبلا یک متغیر داشتیم 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: حیوان را نمی توان به خطای حیوان خانگی فرستاد ! کامپایلر این بار شکایت نکرد، اما در نتیجه یک استثنا دریافت کردیم. ما قبلاً دلیل آن را می دانیم: ما سعی می کنیم یک شی والد را به یک متغیر فرزند اختصاص دهیم. چرا در واقع نمی توان این کار را انجام داد؟ زیرا همه حیوانات حیوان خانگی نیستند. شما یک شی ایجاد کردید Animalو سعی می کنید آن را به یک متغیر اختصاص دهید Pet. اما مثلاً کایوت نیز حیوان اهلی است Animal، اما نیست . Petبه عبارت دیگر، وقتی می نویسید:
Pet pet = (Pet) new Animal();
new Animal()هر حیوانی می تواند آنجا باشد، و لازم نیست اهلی باشد! به طور طبیعی، متغیر شما Pet petفقط برای نگهداری حیوانات خانگی (و فرزندان آنها) مناسب است و نه برای همه. بنابراین، برای چنین مواردی، یک استثنا خاص در جاوا ایجاد شد - 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();
و در مثال قبلی یک شی بود Animal:
Pet pet = (Pet) new Animal();
به یک متغیر نزول نمی توان یک شی اجداد اختصاص داد. برعکس، شما می توانید آن را انجام دهید.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION