JavaRush /Java blogi /Random-UZ /Java tilidagi polimorfizm

Java tilidagi polimorfizm

Guruhda nashr etilgan
OOP haqidagi savollar IT-kompaniyadagi Java dasturchisi lavozimi uchun texnik intervyuning ajralmas qismidir. Ushbu maqolada biz OOP tamoyillaridan biri - polimorfizm haqida gapiramiz. Biz suhbat davomida tez-tez so'raladigan jihatlarga e'tibor qaratamiz, shuningdek, aniqlik uchun kichik misollar keltiramiz.

Polimorfizm nima?

Polimorfizm - dasturning bir xil interfeysga ega ob'ektlardan ushbu ob'ektning o'ziga xos turi haqida ma'lumotsiz bir xil foydalanish qobiliyati. Agar siz polimorfizm nima degan savolga shu tarzda javob bersangiz, sizdan nimani nazarda tutayotganingizni tushuntirishingiz so'raladi. Yana bir bor, bir nechta qo'shimcha savollarni so'ramasdan, suhbatdosh uchun hamma narsani tartibga soling.

Intervyuda Java tilidagi polimorfizm - 1
Biz OOP yondashuvi sinflarga asoslangan ob'ektlarning o'zaro ta'siriga asoslangan Java dasturini yaratishni o'z ichiga olganligidan boshlashimiz mumkin. Sinflar oldindan yozilgan chizmalar (shablonlar) bo'lib, ularga ko'ra dasturdagi ob'ektlar yaratiladi. Bundan tashqari, sinf har doim o'ziga xos turga ega bo'lib, u yaxshi dasturlash uslubi bilan o'z maqsadini nomi bilan "aytib beradi". Bundan tashqari, shuni ta'kidlash mumkinki, Java kuchli terilgan til bo'lganligi sababli, dastur kodi har doim o'zgaruvchilarni e'lon qilishda ob'ekt turini ko'rsatishi kerak. Bunga shuni qo'shingki, qattiq terish kod xavfsizligi va dastur ishonchliligini oshiradi va kompilyatsiya bosqichida turdagi nomuvofiqlik xatolarining (masalan, qatorni raqamga bo'lish urinishi) oldini olishga imkon beradi. Tabiiyki, kompilyator e'lon qilingan turni "bilishi" kerak - bu JDK sinfi yoki biz o'zimiz yaratgan sinf bo'lishi mumkin. Iltimos, suhbatdoshga shuni esda tutingki, dastur kodi bilan ishlashda biz e'lon qilishda nafaqat biz tayinlagan turdagi ob'ektlardan, balki uning avlodlaridan ham foydalanishimiz mumkin. Bu muhim nuqta: biz ko'p turlarga xuddi bitta bo'lgandek munosabatda bo'lishimiz mumkin (agar bu turlar asosiy turdan olingan bo'lsa). Bu shuningdek, superklass turidagi o'zgaruvchini e'lon qilib, biz unga uning avlodlaridan birining qiymatini belgilashimiz mumkinligini anglatadi. Agar siz misol keltirsangiz, suhbatdoshga yoqadi. Ob'ektlar guruhi uchun umumiy (asosiy) bo'lishi mumkin bo'lgan ob'ektni tanlang va undan bir nechta sinflarni meros qilib oling. Asosiy sinf:
public class Dancer {
    private String name;
    private int age;

    public Dancer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void dance() {
        System.out.println(toString() + "I dance like everyone else.");
    }

    @Override
    public String toString() {
        return "Я " + name + ", to me " + age + " years. " ;
    }
}
Avlodlarda asosiy sinf usulini bekor qiling:
public class ElectricBoogieDancer extends Dancer {
    public ElectricBoogieDancer(String name, int age) {
        super(name, age);
    }
// overriding the base class method
    @Override
    public void dance() {
        System.out.println( toString() + "I dance electric boogie!");
    }
}

public class BreakDankDancer extends Dancer{

    public BreakDankDancer(String name, int age) {
        super(name, age);
    }
// overriding the base class method
    @Override
    public void dance(){
        System.out.println(toString() + "I'm breakdancing!");
    }
}
Java-da polimorfizm va dasturda ob'ektlardan foydalanishga misol:
public class Main {

    public static void main(String[] args) {
        Dancer dancer = new Dancer("Anton", 18);

        Dancer breakDanceDancer = new BreakDankDancer("Alexei", 19);// upcast to base type
        Dancer electricBoogieDancer = new ElectricBoogieDancer("Igor", 20); // upcast to base type

        List<Dancer> discotheque = Arrays.asList(dancer, breakDanceDancer, electricBoogieDancer);
        for (Dancer d : discotheque) {
            d.dance();// polymorphic method call
        }
    }
}
Usul kodida satrlarda nima borligini mainko'rsating :
Dancer breakDanceDancer = new BreakDankDancer("Alexei", 19);
Dancer electricBoogieDancer = new ElectricBoogieDancer("Igor", 20);
Biz superklass tipidagi o'zgaruvchini e'lon qildik va unga avlodlardan birining qiymatini berdik. Ehtimol, sizdan nima uchun kompilyator topshiriq belgisining chap va o'ng tomonida e'lon qilingan turlar o'rtasidagi nomuvofiqlik haqida shikoyat qilmaydi, deb so'raladi, chunki Java qattiq terishga ega. Yuqoriga qarab turdagi konvertatsiya bu yerda ishlashini tushuntiring - ob'ektga havola asosiy sinfga havola sifatida talqin etiladi. Bundan tashqari, kompilyator kodda bunday tuzilishga duch kelgan holda, buni avtomatik ravishda va bilvosita bajaradi. DancerMisol kodiga asoslanib, topshiriq belgisining chap tomonida e'lon qilingan sinf turi o'ngda e'lon qilingan bir nechta shakllarga (turlarga) ega ekanligini ko'rsatish mumkin BreakDankDancer, ElectricBoogieDancer. Shakllarning har biri superklass usulida belgilangan umumiy funksionallik uchun o'ziga xos xatti-harakatlarga ega bo'lishi mumkin dance. Ya'ni, supersinfda e'lon qilingan usul uning avlodlarida boshqacha tarzda amalga oshirilishi mumkin. Bunday holda, biz usulni bekor qilish bilan shug'ullanamiz va aynan shu narsa turli shakllarni (xulq-atvorni) yaratadi. Buni bajarish uchun asosiy usul kodini ishga tushirish orqali ko'rishingiz mumkin: Dastur chiqishi Men Antonman, men 18 yoshdaman. Men boshqalar kabi raqsga tushaman. Men Alekseyman, men 19 yoshdaman. Men breykdans! Men Igor, men 20 yoshdaman. Men elektr bujini raqsga tushuraman! Agar biz avlodlarda bekor qilishdan foydalanmasak, unda biz boshqacha xatti-harakatlarga ega bo'lmaymiz. BreakDankDancerMisol uchun, agar biz darslarimiz uchun ElectricBoogieDancerusulni izohlasak dance, dasturning natijasi quyidagicha bo'ladi: men Antonman, men 18 yoshdaman. Men boshqalar kabi raqsga tushaman. Men Alekseyman, men 19 yoshdaman. Men boshqalar kabi raqsga tushaman. Men Igor, men 20 yoshdaman. Men boshqalar kabi raqsga tushaman. BreakDankDancerva bu yangi sinflar yaratishda shunchaki hech qanday nuqta yo'q degan ma'noni anglatadi ElectricBoogieDancer. Java polimorfizmining printsipi aniq nima? Ob'ektni o'ziga xos turini bilmasdan dasturda foydalanish qayerda yashiringan? Bizning misolimizda, bu turdagi d.dance()ob'ektga qo'ng'iroq qilish usuli . Java polimorfizmi, dastur ob'ekt yoki ob'ekt qanday turdagi bo'lishini bilish shart emasligini anglatadi . Asosiysi, bu sinfning avlodi . Va agar biz avlodlar haqida gapiradigan bo'lsak, shuni ta'kidlash kerakki, Java-da meros nafaqat , balki . Endi Java bir nechta merosni qo'llab-quvvatlamasligini yodda tutish vaqti keldi - har bir turda bitta ota-ona (supersinf) va cheksiz miqdordagi avlodlar (quyi sinflar) bo'lishi mumkin. Shuning uchun interfeyslar sinflarga bir nechta funksiyalarni qo'shish uchun ishlatiladi. Interfeyslar merosga nisbatan ob'ektlarning ota-onaga ulanishini kamaytiradi va juda keng qo'llaniladi. Java-da interfeys mos yozuvlar turidir, shuning uchun dastur bu turni interfeys turining o'zgaruvchisi sifatida e'lon qilishi mumkin. Bu misol keltirish uchun yaxshi vaqt. Keling, interfeysni yarataylik: dDancerBreakDankDancerElectricBoogieDancerDancerextendsimplements
public interface Swim {
    void swim();
}
Aniqlik uchun keling, turli xil va bog'liq bo'lmagan ob'ektlarni olaylik va ularda interfeysni amalga oshiramiz:
public class Human implements Swim {
    private String name;
    private int age;

    public Human(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void swim() {
        System.out.println(toString()+"I swim with an inflatable ring.");
    }

    @Override
    public String toString() {
        return "Я " + name + ", to me " + age + " years. ";
    }

}

public class Fish implements Swim{
    private String name;

    public Fish(String name) {
        this.name = name;
    }

    @Override
    public void swim() {
        System.out.println("I'm a fish " + name + ". I swim by moving my fins.");

    }

public class UBoat implements Swim {

    private int speed;

    public UBoat(int speed) {
        this.speed = speed;
    }

    @Override
    public void swim() {
        System.out.println("The submarine is sailing, rotating the propellers, at a speed" + speed + " knots.");
    }
}
Usul main:
public class Main {

    public static void main(String[] args) {
        Swim human = new Human("Anton", 6);
        Swim fish = new Fish("whale");
        Swim boat = new UBoat(25);

        List<Swim> swimmers = Arrays.asList(human, fish, boat);
        for (Swim s : swimmers) {
            s.swim();
        }
    }
}
Interfeysda aniqlangan polimorfik usulni bajarish natijasi ushbu interfeysni amalga oshiruvchi turlarning xatti-harakatlaridagi farqlarni ko'rish imkonini beradi. Ular usulni bajarishning turli natijalaridan iborat swim. Bizning misolimizni o'rganib chiqqandan so'ng, suhbatdosh kodni bajarayotganda nima uchun so'rashi mumkinmain
for (Swim s : swimmers) {
            s.swim();
}
Ushbu sinflarda aniqlangan usullar bizning ob'ektlarimiz uchun chaqiriladimi? Dasturni bajarishda usulning kerakli bajarilishini qanday tanlash mumkin? Ushbu savollarga javob berish uchun biz kechikish (dinamik) bog'lanish haqida gapirishimiz kerak. Bog'lanish deganda biz metod chaqiruvi va uning sinflarda o'ziga xos qo'llanilishi o'rtasida aloqa o'rnatishni nazarda tutamiz. Asosan, kod sinflarda belgilangan uchta usuldan qaysi biri bajarilishini aniqlaydi. Java sukut bo'yicha kech bog'lashdan foydalanadi (erta bog'lashda bo'lgani kabi kompilyatsiya vaqtida emas, balki ish vaqtida). Bu kodni kompilyatsiya qilishda degan ma'noni anglatadi
for (Swim s : swimmers) {
            s.swim();
}
Humankompilyator hali kodning qaysi sinfga tegishli ekanligini yoki uning ichida Fishbajarilishini bilmaydi . Bu faqat dinamik jo'natish mexanizmi - dasturni bajarish jarayonida ob'ekt turini tekshirish va ushbu tur uchun usulning kerakli bajarilishini tanlash tufayli dastur bajarilganda aniqlanadi. Agar sizdan bu qanday amalga oshirilganligi so'ralsa, siz JVM ob'ektlarni yuklash va ishga tushirishda xotirada jadvallar tuzadi va ulardagi o'zgaruvchilarni qiymatlari bilan, ob'ektlarni esa usullari bilan bog'laydi, deb javob berishingiz mumkin. Bundan tashqari, agar ob'ekt meros qilib olingan bo'lsa yoki interfeysni amalga oshirsa, birinchi navbatda uning sinfida bekor qilingan usullarning mavjudligi tekshiriladi. Agar mavjud bo'lsa, ular shu turga bog'lanadi, agar bo'lmasa, sinfda bir daraja yuqori (ota-onada) va shunga o'xshash ko'p darajali ierarxiyada ildizgacha aniqlangan usul qidiriladi. OOPda polimorfizm va uni dastur kodida amalga oshirish haqida gapirganda, biz mavhum sinflar va interfeyslardan foydalangan holda bazaviy sinflarni aniqlash uchun mavhum tavsiflardan foydalanish yaxshi amaliyot ekanligini ta'kidlaymiz. Ushbu amaliyot abstraktsiyadan foydalanishga asoslangan - umumiy xatti-harakatlar va xususiyatlarni ajratib olish va ularni mavhum sinfga qo'shish yoki faqat umumiy xatti-harakatni ajratish - bu holda biz interfeys yaratamiz. Interfeyslar va sinf merosiga asoslangan ob'ektlar ierarxiyasini qurish va loyihalash OOP polimorfizmi tamoyilini bajarish uchun zaruriy shartdir. Java-da polimorfizm va innovatsiyalar masalasiga kelsak, shuni ta'kidlashimiz mumkinki, mavhum sinflar va interfeyslarni yaratishda Java 8 dan boshlab, kalit so'zdan foydalanib, bazaviy sinflarda mavhum usullarning sukut bo'yicha amalga oshirilishini yozish mumkin . Masalan: Uboatswimdefault
public interface Swim {
    default void swim() {
        System.out.println("Just floating");
    }
}
Ba'zan ular polimorfizm printsipi buzilmasligi uchun asosiy sinflarda usullarni e'lon qilish talablari haqida so'rashlari mumkin. Bu erda hamma narsa oddiy: bu usullar statik , shaxsiy va yakuniy bo'lmasligi kerak . Private usulni faqat sinfda mavjud qiladi va siz uni avlodda bekor qila olmaysiz. Static usulni ob'ekt emas, balki sinfning xususiyatiga aylantiradi, shuning uchun superklass usuli har doim chaqiriladi. Final usulni o'zgarmas va merosxo'rlaridan yashirin qiladi.

Java-da polimorfizm bizga nima beradi?

Polimorfizmdan foydalanish bizga nima beradi degan savol ham paydo bo'ladi. Bu erda siz begona o'tlarga chuqur kirmasdan qisqacha javob berishingiz mumkin:
  1. Ob'ektni amalga oshirishni almashtirish imkonini beradi. Sinov shunga asoslanadi.
  2. Dasturning kengaytirilishini ta'minlaydi - kelajak uchun poydevor yaratish ancha osonlashadi. Mavjudlari asosida yangi turlarni qo'shish OOP uslubida yozilgan dasturlarning funksionalligini kengaytirishning eng keng tarqalgan usuli hisoblanadi.
  3. Umumiy turdagi yoki xatti-harakatlarga ega bo'lgan ob'ektlarni bitta to'plam yoki massivga birlashtirish va ularni bir xilda boshqarish imkonini beradi (bizning misollarimizda bo'lgani kabi, hammani raqsga tushirish - usul danceyoki suzish - usul swim).
  4. Yangi turlarni yaratishda moslashuvchanlik: siz ota-onadan usulni qo'llashni tanlashingiz yoki uni bolada bekor qilishingiz mumkin.

Sayohat uchun ajralish so'zlari

Polimorfizm tamoyili juda muhim va keng mavzudir. U Java OOP ning deyarli yarmini va til asoslarining yaxshi qismini qamrab oladi. Siz intervyuda ushbu tamoyilni aniqlashdan qutulolmaysiz. Buni bilmaslik yoki noto'g'ri tushunish, ehtimol, suhbatga nuqta qo'yadi. Shuning uchun, testdan oldin bilimingizni tekshirishga dangasa bo'lmang va kerak bo'lganda uni yangilang.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION