JavaRush /Java блогы /Random-KK /Полиморфизм және оның достары
Viacheslav
Деңгей

Полиморфизм және оның достары

Топта жарияланған
Полиморфизм an objectілі-бағытталған программалаудың негізгі принциптерінің бірі болып табылады. Ол сізге Java-ның күшті теру мүмкіндігін пайдалануға және қолдануға болатын және жөндеуге болатын codeты жазуға мүмкіндік береді. Ол туралы көп айтылды, бірақ бәрі осы шолудан жаңа нәрсені ала алады деп үміттенемін.
Полиморфизм және оның достары - 1

Кіріспе

Java бағдарламалау тілі Oracle компаниясына тиесілі екенін бәріміз білеміз деп ойлаймын. Сондықтан біздің жолымыз мына сайттан басталады: www.oracle.com . Негізгі бетте «Мәзір» бар. Онда «Құжаттама» бөлімінде «Java» бөлімі бар. Тілдің негізгі функцияларына қатысты барлық нәрсе «Java SE құжаттамасына» жатады, сондықтан біз осы бөлімді таңдаймыз. Құжаттама бөлімі соңғы нұсқа үшін ашылады, бірақ әзірге "Басқа шығарылым іздеп жүрсіз бе?" Опцияны таңдайық: JDK8. Парақта біз көптеген әртүрлі опцияларды көреміз. Бірақ біз тілді үйренуге қызығушылық танытамыз: " Java оқулықтары үйрену жолдары ". Бұл бетте біз басқа бөлімді табамыз: « Java тілін үйрену ». Бұл қасиеттілердің ең қасиеттісі, Oracle ұсынған Java негіздері бойынша оқу құралы. Java – an objectіге бағытталған бағдарламалау тілі (OOP), сондықтан тілді үйрену тіпті Oracle веб-сайтында « Объектіге бағытталған бағдарламалау тұжырымдамалары » негізгі ұғымдарын талқылаудан басталады . Атаудың өзінен Java-ның an objectілермен жұмыс істеуге бағытталғаны анық. « Нысан дегеніміз не? » бөлімінде Java тіліндегі нысандар күй мен мінез-құлықтан тұратыны анық. Біздің банктік шотымыз бар деп елестетіңіз. Шоттағы ақша сомасы - күй, ал бұл күймен жұмыс істеу әдістері - мінез-құлық. Нысандар қандай да бір түрде сипатталуы керек (олардың күйі мен мінез-құлқы қандай болуы мүмкін екенін айтыңыз) және бұл сипаттама класс болып табылады . Қандай да бір класстың an objectісін жасағанда, біз осы классты көрсетеміз және ол « an object түрі » деп аталады. Демек, Java тілі « 4 тарау. Түрлер, мәндер және айнымалылар » бөліміндегі Java тілінің спецификациясында айтылғандай, қатты терілген тіл деп айтылады . Java тілі OOP концепцияларына сүйенеді және кеңейтілген кілт сөзі арқылы мұраны қолдайды. Неліктен кеңейту? Өйткені мұрагерлікпен еншілес сынып ата-аналық сыныптың мінез-құлқы мен күйін мұраға алады және оларды толықтыра алады, яғни. базалық класстың функционалдығын кеңейту. Интерфейсті сынып сипаттамасында да implements кілт сөзі арқылы көрсетуге болады. Класс интерфейсті жүзеге асырған кезде, бұл сыныптың қандай да бір келісім-шартқа сәйкес келетінін білдіреді - бағдарламашының басқа ортаға сыныптың белгілі бір мінез-құлқы бар екендігі туралы мәлімдемесі. Мысалы, ойнатқышта әртүрлі түймелер бар. Бұл түймелер ойнатқыштың әрекетін басқаруға арналған интерфейс болып табылады және әрекет ойнатқыштың ішкі күйін өзгертеді (мысалы, дыбыс деңгейі). Бұл жағдайда күй мен мінез-құлық сипаттама ретінде класс береді. Егер класс интерфейсті жүзеге асырса, онда осы класстың көмегімен жасалған нысан тек класс бойынша ғана емес, интерфейс арқылы да тип бойынша сипатталуы мүмкін. Мысал қарастырайық:
public class MusicPlayer {

    public static interface Device {
        public void turnOn();
        public void turnOff();
    }

    public static class Mp3Player implements Device {
        public void turnOn() {
            System.out.println("On. Ready for mp3.");
        }
        public void turnOff() {
            System.out.println("Off");
        }
    }

    public static class Mp4Player extends Mp3Player {
        @Override
        public void turnOn() {
            System.out.println("On. Ready for mp3/mp4.");
        }
    }

    public static void main(String []args) throws Exception{
        // Какое-то устройство (Тип = Device)
        Device mp3Player = new Mp3Player();
        mp3Player.turnOn();
        // У нас есть mp4 проигрыватель, но нам от него нужно только mp3
        // Пользуемся им How mp3 проигрывателем (Тип = Mp3Player)
        Mp3Player mp4Player = new Mp4Player();
        mp4Player.turnOn();
    }
}
Түр - өте маңызды сипаттама. Ол нысанмен қалай жұмыс істейтінімізді айтады, яғни. an objectіден қандай мінез-құлық күтеміз. Мінез – бұл әдістер. Сондықтан әдістерді түсінейік. Oracle веб-сайтында әдістердің Oracle оқулығында өз бөлімі бар: " Әдістерді анықтау ". Мақаладан алып тастау керек бірінші нәрсе: Әдістің қолтаңбасы - әдістің атауы және параметрлер түрлері :
Полиморфизм және оның достары - 2
Мысалы, әдістің public void әдісін (Object o) жариялағанда, қолтаңба әдістің аты және Object параметрінің түрі болады. Қайтару түрі қолтаңбада ЕМЕС. Бұл маңызды! Әрі қарай, бастапқы codeымызды құрастырайық. Белгілі болғандай, бұл үшін codeты сынып атауы және java кеңейтімі бар файлда сақтау керек. Java codeы Java виртуалды машинасы (JVM) орындай алатын кейбір аралық пішімге " javac " компиляторы арқылы құрастырылады . Бұл аралық пішім byte code деп аталады және .class кеңейтімі бар файлдарда қамтылған. Компиляциялау командасын орындаймыз: javac MusicPlayer.java java codeы құрастырылғаннан кейін оны орындауға болады. Бастау үшін « java » утorтасын пайдаланып, сынып файлында берілген byte-codeты орындау үшін java виртуалды машина процесі іске қосылады. Қолданбаны іске қосу пәрменін орындаймыз: java MusicPlayer. Экранда println әдісінің енгізу параметрінде көрсетілген мәтінді көреміз. Бір қызығы, byte-code .class кеңейтімі бар файлда болса, біз оны « javap » утorтасының көмегімен көре аламыз. <ocde>javap -c MusicPlayer пәрменін орындаймыз:
Полиморфизм және оның достары - 3
Байтеcodeтан түрі класс көрсетілген нысан арқылы әдісті шақыру арқылы жүзеге асырылатынын invokevirtualжәне компилятор қандай әдіс қолтаңбасын пайдалану керектігін есептегенін көреміз. Неліктен invokevirtual? Өйткені виртуалды әдістің шақыруы (invoke шақыру деп аударылады) бар. Виртуалды әдіс дегеніміз не? Бұл бағдарламаны орындау кезінде денесін қайта анықтауға болатын әдіс. Сізде белгілі бір кілт (әдіс қолтаңбасы) мен әдістің негізгі бөлігі (codeы) арасындағы сәйкестік тізімі бар екенін елестетіп көріңіз. Ал әдістің кілті мен денесінің арасындағы бұл сәйкестік бағдарламаның орындалу барысында өзгеруі мүмкін. Сондықтан әдіс виртуалды. Әдепкі бойынша, Java тілінде статикалық ЕМЕС, түпкілікті емес және жеке ЕМЕС әдістер виртуалды болып табылады. Осының арқасында Java полиморфизмнің an objectіге бағытталған бағдарламалау принципін қолдайды. Сіз түсінген боларсыз, бұл біздің бүгінгі шолуымыз туралы.

Полиморфизм

Oracle веб-сайтында олардың ресми оқулығында жеке бөлім бар: « Полиморфизм ». Java тілінде полиморфизмнің қалай жұмыс істейтінін көру үшін Java Online Compiler қолданбасын қолданайық . Мысалы, бізде Java тілінде санды білдіретін кейбір абстрактілі сынып саны бар. Ол не мүмкіндік береді? Оның барлық мұрагерлерге ие болатын негізгі әдістері бар. Санның мұрагері кез келген адам сөзбе-сөз айтады: «Мен санмын, сіз менімен сан ретінде жұмыс істей аласыз». Мысалы, кез келген мұрагер үшін оның Integer мәнін алу үшін intValue() әдісін пайдалануға болады. Сан үшін java api-ге қарасаңыз, әдіс абстрактілі екенін көре аласыз, яғни Санның әрбір мұрагері осы әдісті өзі жүзеге асыруы керек. Бірақ бұл бізге не береді? Мысал қарастырайық:
public class HelloWorld {

    public static int summ(Number first, Number second) {
        return first.intValue() + second.intValue();
    }

    public static void main(String []args){
        System.out.println(summ(1, 2));
        System.out.println(summ(1L, 4L));
        System.out.println(summ(1L, 5));
        System.out.println(summ(1.0, 3));
    }
}
Мысалдан көріп отырғанымыздай, полиморфизмнің арқасында біз Санның ұрпағы болатын кез келген түрдегі аргументтерді енгізу ретінде қабылдайтын әдісті жаза аламыз (біз Санды ала алмаймыз, өйткені ол абстрактілі класс). Ойыншы мысалында болғандай, бұл жағдайда біз Сан сияқты бір нәрсемен жұмыс істегіміз келетінін айтамыз. Сан болып табылатын кез келген адам оның бүтін мәнін бере алуы керек екенін білеміз. Ал бізге бұл жеткілікті. Біз нақты нысанды жүзеге асырудың егжей-тегжейіне тоқталғымыз келмейді және бұл нысанмен Санның барлық ұрпақтарына ортақ әдістер арқылы жұмыс жасағымыз келеді. Бізге қолжетімді әдістер тізімі компиляция уақытында түрі бойынша анықталады (byteеcodeта бұрын көргеніміздей). Бұл жағдайда біздің түріміз Сан болады. Мысалдан көріп отырғанымыздай, біз әртүрлі типтегі әртүрлі сандарды беріп жатырмыз, яғни қосынды әдісі кіріс ретінде Integer, Long және Double қабылдайды. Бірақ олардың барлығына ортақ нәрсе - олар абстрактілі Санның ұрпақтары, сондықтан олардың intValue әдісіндегі мінез-құлқын жоққа шығарады, өйткені әрбір нақты түр бұл түрді бүтін санға қалай шығару керектігін біледі. Мұндай полиморфизм ағылшын тіліндегі Overriding деп аталатын қайта анықтау арқылы жүзеге асырылады.
Полиморфизм және оның достары - 4
Қайта анықтау немесе динамикалық полиморфизм. Сонымен, HelloWorld.java файлын келесі мазмұнмен сақтаудан бастайық:
public class HelloWorld {
    public static class Parent {
        public void method() {
            System.out.println("Parent");
        }
    }
    public static class Child extends Parent {
        public void method() {
            System.out.println("Child");
        }
    }

    public static void main(String[] args) {
        Parent parent = new Parent();
        Parent child = new Child();
        parent.method();
        child.method();
    }
}
Біз жасайық javac HelloWorld.javaжәне javap -c HelloWorld:
Полиморфизм және оның достары - 5
Көріп отырғаныңыздай, шақыру әдісі бар жолдардың byte codeында шақыру әдісіне бірдей сілтеме көрсетілген invokevirtual (#6). Қанекей мынаны істейік java HelloWorld. Көріп отырғанымыздай, ата-ана және еншілес айнымалылар Parent типімен жарияланады, бірақ іске асырудың өзі айнымалыға қандай нысан тағайындалғанына (яғни, нысанның қандай түріне) сәйкес шақырылады. Бағдарламаны орындау кезінде (орындау уақытында да айтады) JVM an objectіге байланысты бірдей қолтаңбаны қолданатын әдістерді шақырған кезде әртүрлі әдістерді орындады. Яғни, сәйкес қолтаңбаның кілтін пайдаланып, біз алдымен бір әдіс денесін алдық, содан кейін екіншісін алдық. Айнымалыда қандай нысан бар екеніне байланысты. Бағдарламаны орындау кезінде қандай әдіс шақырылатынын анықтауды кешіктіру немесе динамикалық байланыстыру деп те атайды. Яғни, қолтаңба мен әдіс денесінің арасындағы сәйкестік әдіс шақырылатын нысанға байланысты динамикалық түрде орындалады. Әрине, сіз сыныптың статикалық мүшелерін (Сынып мүшесі), сондай-ақ жеке немесе соңғы қатынас түрі бар сынып мүшелерін қайта анықтай алмайсыз. @Override annotationлары әзірлеушілерге де көмектеседі. Бұл компиляторға осы сәтте біз ата-баба әдісінің әрекетін жоққа шығаратынымызды түсінуге көмектеседі. Егер әдіс қолтаңбасында қателік жасасақ, компилятор бұл туралы бізге бірден айтып береді. Мысалы:
public static class Parent {
        public void method() {
            System.out.println("parent");
        }
}
public static class Child extends Parent {
        @Override
        public void method(String text) {
            System.out.println("child");
        }
}
Қатемен компиляцияланбайды: қате: әдіс супертүрден әдісті қайта анықтамайды немесе жүзеге асырмайды
Полиморфизм және оның достары - 6
Қайта анықтау « коварианттық » ұғымымен де байланысты . Мысал қарастырайық:
public class HelloWorld {
    public static class Parent {
        public Number method() {
            return 1;
        }
    }
    public static class Child extends Parent {
        @Override
        public Integer method() {
            return 2;
        }
    }

    public static void main(String[] args) {
        System.out.println(new Child().method());
    }
}
Көрініп тұрған абструкцияға қарамастан, мағынасы басымдыққа ие болған кезде тек ата-бабада көрсетілген түрді ғана емес, сонымен қатар нақтырақ түрін де қайтара алатынымызға байланысты. Мысалы, ата-баба Санды қайтарды, ал біз Integer - Санның ұрпағын қайтара аламыз. Әдістің лақтырылуында жарияланған ерекшеліктерге де қатысты. Мұрагерлер әдісті қайта анықтай алады және шығарылған ерекше жағдайды нақтылай алады. Бірақ олар кеңейе алмайды. Яғни, егер ата-ана IOException шығарса, онда біз дәлірек EOFException лақтыра аламыз, бірақ біз Ерекше жағдайды жасай алмаймыз. Сол сияқты, ауқымды тарылта алмайсыз және қосымша шектеулер қоя алмайсыз. Мысалы, статикалық қосу мүмкін емес.
Полиморфизм және оның достары - 7

Жасыру

« Жасыру » деген де бар . Мысалы:
public class HelloWorld {
    public static class Parent {
        public static void method() {
            System.out.println("Parent");
        }
    }
    public static class Child extends Parent {
        public static void method() {
            System.out.println("Child");
        }
    }

    public static void main(String[] args) {
        Parent parent = new Parent();
        Parent child = new Child();
        parent.method();
        child.method();
    }
}
Егер сіз бұл туралы ойласаңыз, бұл өте айқын нәрсе. Кластың статикалық мүшелері сыныпқа жатады, яғни. айнымалының түріне. Сондықтан, егер бала Ата-ана типінде болса, әдіс балаға емес, Ата-анаға шақырылатыны қисынды. Бұрынғыдай byte codeқа қарасақ, статикалық әдіс invokestatic көмегімен шақырылатынын көреміз. Бұл JVM-ге invokevirtual немесе invokeinterface сияқты әдіс кестесінде емес, түрін қарау керектігін түсіндіреді.
Полиморфизм және оның достары – 8

Шамадан тыс жүктеу әдістері

Java Oracle оқулығында тағы не көреміз? Бұрын зерттелген « Әдістерді анықтау » бөлімінде шамадан тыс жүктеу туралы бір нәрсе бар. Бұл не? Орыс тілінде бұл «әдісті шамадан тыс жүктеу», ал мұндай әдістер «шамадан тыс жүктелу» деп аталады. Сонымен, әдісті шамадан тыс жүктеу. Бір қарағанда, бәрі қарапайым. Онлайн Java компиляторын ашайық, мысалы, tutorialspoint online java компиляторы .
public class HelloWorld {

	public static void main(String []args){
		HelloWorld hw = new HelloWorld();
		hw.say(1);
		hw.say("1");
	}

	public static void say(Integer number) {
		System.out.println("Integer " + number);
	}
	public static void say(String number) {
		System.out.println("String " + number);
	}
}
Демек, мұнда бәрі қарапайым болып көрінеді. Oracle оқулығында айтылғандай, шамадан тыс жүктелген әдістер (бұл жағдайда айту әдісі) әдіске жіберілген аргументтердің саны мен түрі бойынша ерекшеленеді. Бірдей атау мен бірдей аргумент түрлерінің бірдей санын жариялай алмайсыз, себебі компилятор оларды бір-бірінен ажырата алмайды. Бірден өте маңызды нәрсені атап өткен жөн:
Полиморфизм және оның достары – 9
Яғни, шамадан тыс жүктеу кезінде компилятор дұрыстығын тексереді. Бұл маңызды. Бірақ компилятор белгілі бір әдісті шақыру қажет екенін қалай анықтайды? Ол Java тілінің спецификациясында сипатталған "Ең ерекше әдіс" ережесін пайдаланады: " 15.12.2.5. Ең ерекше әдісті таңдау ". Оның қалай жұмыс істейтінін көрсету үшін Oracle Certified Professional Java Programmer үлгісін алайық:
public class Overload{
  public void method(Object o) {
    System.out.println("Object");
  }
  public void method(java.io.FileNotFoundException f) {
    System.out.println("FileNotFoundException");
  }
  public void method(java.io.IOException i) {
    System.out.println("IOException");
  }
  public static void main(String args[]) {
    Overload test = new Overload();
    test.method(null);
  }
}
Мына жерден мысал келтіріңіз: https://github.com/stokito/OCPJP/blob/master/src/ru/habrahabr/blogs/java/OCPJP1/question1/Overload.j... Көріп отырғаныңыздай, біз өтіп жатырмыз. әдіске нөл. Компилятор ең нақты типті анықтауға тырысады. Нысан қолайлы емес, себебі бәрі одан мұрагер. Ілгері жүру. Ерекшеліктердің 2 класы бар. java.io.IOException қарап көрейік және «Тікелей белгілі ішкі сыныптарда» FileNotFoundException бар екенін көрейік. Яғни, FileNotFoundException ең ерекше түрі болып шықты. Сондықтан нәтиже «FileNotFoundException» жолының шығысы болады. Бірақ егер біз IOException-ті EOFException-мен ауыстырсақ, бізде тип ағашында иерархияның бірдей деңгейінде екі әдіс бар, яғни олардың екеуі үшін IOException ата-ана болып табылады. Компилятор қай әдісті шақыру керектігін таңдай алмайды және компиляция қатесін жібереді: reference to method is ambiguous. Тағы бір мысал:
public class Overload{
    public static void method(int... array) {
        System.out.println("1");
    }

    public static void main(String args[]) {
        method(1, 2);
    }
}
Ол 1 шығарады. Мұнда сұрақтар жоқ. int... түрі - vararg https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html және шын мәнінде "синтаксистік қанттан" басқа ештеңе емес және шын мәнінде int болып табылады. .. массив int[] массиві ретінде оқылады. Енді әдісті қоссақ:
public static void method(long a, long b) {
	System.out.println("2");
}
Содан кейін ол 1 емес, 2 көрсетеді, өйткені біз 2 санды өткізіп жатырмыз және 2 аргумент бір массивке қарағанда жақсы сәйкес келеді. Егер әдісті қоссақ:
public static void method(Integer a, Integer b) {
	System.out.println("3");
}
Содан кейін біз әлі де 2-ні көреміз. Өйткені бұл жағдайда қарабайыр сандар Integer ішіндегі боксқа қарағанда дәлірек сәйкес келеді. Дегенмен, егер біз орындасақ, method(new Integer(1), new Integer(2));ол басып шығарады 3. Java-дағы конструкторлар әдістерге ұқсас және олар қолтаңбаны алу үшін де пайдаланылуы мүмкін болғандықтан, шамадан тыс жүктелген әдістер сияқты оларға бірдей «шамадан тыс жүктеу рұқсаты» ережелері қолданылады. Java тілінің спецификациясы бұл туралы " 8.8.8. Конструкторды шамадан тыс жүктеу " тармағында айтады. Әдістің шамадан тыс жүктелуі = Ерте байланыстыру (статикалық байланыстыру) Статикалық байланыстыру немесе динамикалық байланыстыру деп те белгілі ерте және кеш байланыстыру туралы жиі естуге болады. Олардың арасындағы айырмашылық өте қарапайым. Ерте - компиляция, кеш - бағдарлама орындалатын сәт. Сондықтан ерте байланыстыру (статикалық байланыстыру) дегеніміз компиляция уақытында кімге қандай әдіс шақырылатынын анықтау. Кешіктірілген байланыстыру (динамикалық байланыстыру) - бұл бағдарламаны орындау кезінде қандай әдісті тікелей шақыру керектігін анықтау. Бұрын көргеніміздей (IOException-ты EOFException-қа өзгерткен кезде), егер компилятор қай жерде қоңырау шалу керектігін түсіне алмайтындай әдістерді шамадан тыс жүктесек, біз компиляция уақытында қатені аламыз: әдіске сілтеме түсініксіз. Ағылшын тілінен аударғанда екіұшты сөз көп мағыналы немесе белгісіз, нақты емес дегенді білдіреді. Шамадан тыс жүктеме ерте байланыстырады, өйткені тексеру компиляция уақытында орындалады. Қорытындыларымызды растау үшін « 8.4.9. Шамадан тыс жүктелу » тарауындағы Java тілінің сипаттамасын ашайық :
Полиморфизм және оның достары – 10
Компиляция кезінде әдістің қолтаңбасын анықтау үшін аргументтердің түрлері мен саны туралы ақпарат (құрастыру кезінде қол жетімді) пайдаланылады екен. Егер әдіс нысан әдістерінің бірі болса (яғни, даналық әдіс), нақты әдіс шақыруы динамикалық әдісті іздеу (яғни, динамикалық байланыстыру) арқылы орындалу уақытында анықталады. Түсінікті болу үшін бұрын талқыланғанға ұқсас мысалды алайық:
public class HelloWorld {
    public void method(int intNumber) {
        System.out.println("intNumber");
    }
    public void method(Integer intNumber) {
        System.out.println("Integer");
    }
    public void method(String intNumber) {
        System.out.println("Number is: " + intNumber);
    }

    public static void main(String args[]) {
        HelloWorld test = new HelloWorld();
        test.method(2);
    }
}
Осы codeты HelloWorld.java файлына сақтап, оны пайдаланып компиляция жасайық javac HelloWorld.java Енді мына пәрменді орындау арқылы компиляторымыз byte codeта не жазғанын көрейік: javap -verbose HelloWorld.
Полиморфизм және оның достары – 11
Айтылғандай, компилятор болашақта кейбір виртуалды әдіс шақырылатынын анықтады. Яғни, әдіс денесі орындалу уақытында анықталады. Бірақ құрастыру кезінде барлық үш әдістің ішінен компилятор ең қолайлысын таңдады, сондықтан ол нөмірді көрсетті:"invokevirtual #13"
Полиморфизм және оның достары - 12
Бұл қандай әдістеме? Бұл әдіске сілтеме. Шамамен айтқанда, бұл іске қосу уақытында Java виртуалды машинасы орындау үшін қандай әдісті іздеу керектігін анықтай алатын кейбір анықтама. Қосымша мәліметтерді супер мақаладан табуға болады: « JVM шамадан тыс жүктеу және ішкі анықтау әдісін қалай өңдейді ».

Қорытындылау

Сонымен, Java тілі an objectіге бағытталған тіл ретінде полиморфизмді қолдайтынын білдік. Полиморфизм статикалық (статикалық байланыстыру) немесе динамикалық (динамикалық байланыстыру) болуы мүмкін. Ерте байланыстыру деп те белгілі статикалық полиморфизммен компилятор қай әдісті және қайда шақыру керектігін анықтайды. Бұл шамадан тыс жүктеме сияқты механизмді пайдалануға мүмкіндік береді. Әдістің бұрын есептелген қолтаңбасына негізделген динамикалық полиморфизммен, сондай-ақ кеш байланыстыру деп те белгілі, әдіс қай нысан пайдаланылатынына (яғни, қандай нысан әдісі шақырылатынына) негізделген орындау уақытында есептеледі. Бұл механизмдердің қалай жұмыс істейтінін byte codeының көмегімен көруге болады. Шамадан тыс жүктеу әдіс қолтаңбаларына қарайды және шамадан тыс жүктемені шешу кезінде ең нақты (ең дәл) опция таңдалады. Қайта анықтау қандай әдістер қолжетімді екенін анықтау үшін түрге қарайды және әдістердің өзі нысан негізінде шақырылады. Тақырып бойынша материалдармен қатар: #Вячеслав
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION