CodeGym /وبلاگ جاوا /Random-FA /متدها در جاوا
John Squirrels
مرحله
San Francisco

متدها در جاوا

در گروه منتشر شد
دوباره سلام! در آخرین درس با کلاس ها و سازنده ها آشنا شدیم و یاد گرفتیم که چگونه خودمان را ایجاد کنیم. امروز با روش‌های جاوا که بخشی ضروری از کلاس‌ها است، بهتر آشنا می‌شویم. Methods در جاوا مجموعه ای از دستورات است که به شما امکان می دهد عملیات خاصی را در یک برنامه انجام دهید. به عبارت دیگر، یک متد یک تابع است. کاری که کلاس شما قادر به انجام آن است. در سایر زبان های برنامه نویسی، متدها اغلب "توابع" نامیده می شوند، اما در جاوا کلمه "متد" بیشتر رایج است. :) اگر به خاطر داشته باشید، در درس آخر ما روش های ساده ای را برای کلاس Cat ایجاد کردیم تا گربه های ما بتوانند میو و پرش کنند:
public class Cat {

    String name;
    int age;

    public void sayMeow() {
        System.out.println("Meow!");
    }

    public void jump() {
        System.out.println("Pounce!");
    }

    public static void main(String[] args) {
        Cat smudge = new Cat();
        smudge.age = 3;
        smudge.name = "Smudge";

        smudge.sayMeow();
        smudge.jump();
    }
}
sayMeow() و jump() متدهای کلاس ما هستند. و اجرای این روش ها منجر به خروجی کنسول زیر می شود:
Meow!
Pounce!
روش های ما بسیار ساده هستند: آنها به سادگی متن را به کنسول ارسال می کنند. اما در جاوا، متدها وظیفه مهمی دارند: آنها اقداماتی را روی داده های یک شی انجام می دهند. آنها داده های شی را تغییر می دهند، آن را تبدیل می کنند، نمایش می دهند و کارهای دیگری با آن انجام می دهند. روش های فعلی ما با داده های شی Cat کاری انجام نمی دهند . بیایید به یک مثال گویاتر نگاه کنیم:
public class Truck {

    int length;
    int width;
    int height;
    int weight;

    public int getVolume() {
        int volume = length * width * height;
        return volume;
    }
}
به عنوان مثال، در اینجا ما یک کلاس داریم که یک کامیون را نشان می دهد . نیمه کامیون دارای طول، عرض، ارتفاع و وزن است (که بعداً به آن نیاز خواهیم داشت). در متد getVolume() ما محاسبات را انجام می دهیم و داده های جسم خود را به عددی تبدیل می کنیم که حجم آن را نشان می دهد (طول، عرض و ارتفاع را ضرب می کنیم). این عدد نتیجه روش خواهد بود. توجه داشته باشید که اعلان متد به صورت public int getVolume نوشته شده است . یعنی این روش باید یک int برگرداند . مقدار برگشتی متد را محاسبه کردیم و اکنون باید آن را به برنامه ای که متد ما را فراخوانی کرده است برگردانیم. برای برگرداندن نتیجه یک متد در جاوا، از کلمه کلیدی return استفاده می کنیم. حجم بازگشت؛

پارامترهای روش جاوا

هنگام فراخوانی متد، می توانیم مقادیری به نام "Arguments" را به متد ارسال کنیم. اعلان یک متد شامل لیستی از متغیرها است که نوع و ترتیب متغیرهایی را که متد می تواند بپذیرد به ما می گوید. این لیست "پارامترهای روش" نامیده می شود. متد getVolume() کلاس Truck ما در حال حاضر هیچ پارامتری را تعریف نمی کند، بنابراین بیایید سعی کنیم مثال کامیون خود را گسترش دهیم. یک کلاس جدید به نام BridgeOfficer ایجاد کنید . این یک افسر پلیس در حال انجام وظیفه در یک پل است که تمام کامیون های عبوری را بررسی می کند تا ببیند آیا بار آنها از وزن مجاز بیشتر است یا خیر.
public class BridgeOfficer {

    int maxWeight;

    public BridgeOfficer(int normalWeight) {
        this.maxWeight = normalWeight;
    }

    public boolean checkTruck(Truck truck) {
        if (truck.weight > maxWeight) {
            return false;
        } else {
            return true;
        }
    }
}
روش checkTruck یک آرگومان، یک شی Truck را می‌پذیرد و تعیین می‌کند که آیا افسر به کامیون اجازه می‌دهد روی پل برود یا نه. در داخل روش، منطق به اندازه کافی ساده است: اگر وزن کامیون از حداکثر مجاز بیشتر شود، روش false را برمی‌گرداند . باید جاده دیگری پیدا کند:( اگر وزن کمتر یا مساوی حداکثر باشد، می تواند عبور کند، و متد true را برمی گرداند . اگر عبارات "بازگشت" یا "روش یک را برمی گرداند" کاملاً متوجه نشدید. ارزش" با این حال، اجازه دهید کمی از برنامه نویسی فاصله بگیریم و آنها را با استفاده از یک مثال ساده از زندگی واقعی در نظر بگیریم. :) فرض کنید مریض شده اید و چند روز در خانه می مانید. شما با برگه پزشک خود به حسابداری مراجعه کنید، زیرا قرار است مرخصی استعلاجی پرداخت شود. اگر این وضعیت را با متدها مقایسه کنیم، حسابدار یک متد ()paySickLeave دارد . شما یک یادداشت دکتر را به عنوان استدلال به این روش می دهید (بدون آن، روش کار نمی کند و پولی دریافت نمی کنید!). سپس محاسبات لازم در داخل روش با استفاده از یادداشت شما انجام می شود (حسابدار از آن برای محاسبه مبلغی که شرکت باید به شما پرداخت کند) انجام می شود و نتیجه کار شما (مبلغی از پول) به شما برمی گردد. برنامه ما به روشی مشابه کار می کند. یک متد را فراخوانی می کند، داده ها را به آن ارسال می کند و در نهایت نتیجه را دریافت می کند. در اینجا متد main() برنامه BridgeOfficer ما آمده است :
public static void main(String[] args) {
    Truck first = new Truck();
    first.weight = 10000;
    Truck second = new Truck();
    second.weight = 20000;

    BridgeOfficer officer = new BridgeOfficer(15000);
    System.out.println("Truck 1! Can I go, officer?");
    boolean canFirstTruckGo = officer.checkTruck(first);
    System.out.println(canFirstTruckGo);

    System.out.println();

    System.out.println("Truck 2! And can I?");
    boolean canSecondTruckGo = officer.checkTruck(second);
    System.out.println(canSecondTruckGo);
}
ما دو کامیون با بارهای 10000 و 20000 ایجاد می کنیم. و پلی که افسر در آن کار می کند حداکثر 15000 وزن دارد. برنامه متد officer.checkTruck(first) را فراخوانی می کند . متد همه چیز را محاسبه می کند و سپس true را برمی گرداند که برنامه سپس در متغیر بولی canFirstTruckGo ذخیره می کند . اکنون می توانید هر کاری که می خواهید با آن انجام دهید (همانطور که می توانید با پولی که حسابدار به شما داده است). در پایان روز، کد
boolean canFirstTruckGo = officer.checkTruck(first);
به پایان می رسد
boolean canFirstTruckGo =  true;
در اینجا یک نکته بسیار مهم وجود دارد: دستور return نه تنها مقدار بازگشتی متد را برمی گرداند، بلکه اجرای متد را نیز متوقف می کند! هر کدی که بعد از عبارت return بیاید اجرا نمی شود!
public boolean checkTruck(Truck truck) {

    if (truck.weight > maxWeight) {
        return false;
        System.out.println("Turn around, you're overweight!");
    } else {
        return true;
        System.out.println("Everything looks good, go ahead!");
    }
}
نظرات افسر نمایش داده نمی شود، زیرا روش قبلاً نتیجه داده و خاتمه یافته است! برنامه به محلی که متد فراخوانی شده است برمی گردد. لازم نیست برای این کار دقت کنید: کامپایلر جاوا به اندازه کافی هوشمند است که هنگام تلاش برای نوشتن کد پس از دستور بازگشت، خطا ایجاد کند .

Avengers: Parameter War

شرایطی وجود دارد که ما چندین روش برای فراخوانی یک متد می خواهیم. چرا هوش مصنوعی خودمان را ایجاد نکنیم؟ آمازون الکسا دارد، اپل سیری دارد، پس چرا ما یکی نداشته باشیم؟ :) در فیلم مرد آهنی، تونی استارک هوش مصنوعی باورنکردنی خود، جارویس را خلق می کند. بیایید به آن شخصیت فوق العاده ادای احترام کنیم و هوش مصنوعی خود را به افتخار او نام گذاری کنیم. :) اولین کاری که باید انجام دهیم این است که به جارویس بیاموزیم که به افرادی که وارد اتاق می شوند سلام کند (عجیب خواهد بود اگر چنین عقل شگفت انگیزی بی ادب باشد).
public class Jarvis {

    public void sayHi(String name) {
        System.out.println("Good evening, " + name + ". How are you?");
    }

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark");
    }
}
خروجی کنسول:
Good evening, Tony Stark. How are you?
خیلی خوب! جارویس اکنون می تواند از مهمانان پذیرایی کند. البته، بیشتر اوقات استاد او، تونی استارک خواهد بود. اما اگر تنها نیاید چه می شود! متد sayHi() ما فقط یک آرگومان را می پذیرد. و بنابراین فقط می تواند به یک نفر که وارد اتاق می شود سلام کند و دیگری را نادیده بگیرد. خیلی مودب نیست، موافق نیستی؟ :/

روش جاوا اضافه بار

در این حالت، می‌توانیم با نوشتن 2 روش با نام مشابه، اما پارامترهای مختلف، مشکل را حل کنیم:
public class Jarvis {

    public void sayHi(String firstGuest) {
        System.out.println("Good evening, " + firstGuest + ". How are you?");
    }

    public void sayHi(String firstGuest, String secondGuest) {
        System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
    }
}
به این روش اضافه بار می گویند. بارگذاری بیش از حد روش به برنامه ما امکان می دهد انعطاف پذیرتر باشد و روش های مختلف کار را در خود جای دهد. بیایید نحوه عملکرد آن را مرور کنیم:
public class Jarvis {

    public void sayHi(String firstGuest) {
        System.out.println("Good evening, " + firstGuest + ". How are you?");
    }

    public void sayHi(String firstGuest, String secondGuest) {
        System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
    }

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark");
        jarvis.sayHi("Tony Stark", "Captain America");
    }
}
خروجی کنسول:
Good evening, Tony Stark. How are you?
Good evening, Tony Stark and Captain America. How are you?
عالی بود هر دو نسخه کار کردند :) اما ما مشکل را حل نکردیم! اگر سه مهمان باشد چه؟ البته می‌توانیم متد sayHi() را دوباره بارگذاری کنیم تا نام سه مهمان را بپذیرد. اما می تواند 4 یا 5 باشد. تمام راه تا بی نهایت. آیا راه بهتری برای آموزش جارویس برای مدیریت هر تعداد نام، بدون بارگذاری بیش از حد متد sayHi() وجود ندارد ؟ :/ البته هست! اگر نبود، به نظر شما جاوا محبوب ترین زبان برنامه نویسی در جهان بود؟ ;)
public void sayHi(String...names) {

    for (String name: names) {
        System.out.println("Good evening, " + name + ". How are you?");
    }
}
وقتی از ( String... names ) به عنوان پارامتر استفاده می شود، نشان می دهد که مجموعه ای از رشته ها به متد ارسال می شود. لازم نیست از قبل مشخص کنیم که چه تعداد خواهد بود، بنابراین اکنون روش ما بسیار انعطاف پذیرتر است:
public class Jarvis {

    public void sayHi(String...names) {
        for (String name: names) {
            System.out.println("Good evening, " + name + ". How are you?");
        }
    }

    public static void main(String[] args) {
        Jarvis jarvis = new Jarvis();
        jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
    }
}
خروجی کنسول:
Good evening, Tony Stark. How are you?
Good evening, Captain America. How are you?
Good evening, Black Widow. How are you?
Good evening, Hulk. How are you?
برخی از کدهای اینجا برای شما ناآشنا خواهد بود، اما نگران آن نباشید. این در هسته خود ساده است: روش هر نام را به نوبه خود می گیرد و به هر مهمان سلام می کند! به علاوه، آن را با هر تعداد رشته های عبور کار می کند! دو، ده، حتی هزار - این روش با هر تعداد مهمان به درستی کار خواهد کرد. خیلی راحت تر از بارگذاری بیش از حد روش برای همه احتمالات، فکر نمی کنید؟ :) اینم یه نکته مهم دیگه: ترتیب استدلال ها مهمه! فرض کنید روش ما یک رشته و یک عدد می گیرد:
public class Person {

    public static void sayYourAge(String greeting, int age) {
        System.out.println(greeting + " " + age);
    }

    public static void main(String[] args) {
        sayYourAge("My age is ", 33);
        sayYourAge(33, "My age is "); // Error!
    }
}
اگر متد sayYourAge کلاس Person یک رشته و یک عدد را به عنوان ورودی دریافت کند، برنامه باید آنها را به ترتیب خاص ارسال کند! اگر آنها را به ترتیب دیگری ارسال کنیم، کامپایلر خطا ایجاد می کند و فرد نمی تواند سن خود را بگوید. ضمنا سازنده ها هم که در درس آخر بهشون پرداختیم روش هستن! شما همچنین می توانید آنها را بیش از حد بارگذاری کنید (یعنی چندین سازنده با مجموعه های مختلف پارامترها ایجاد کنید) و ترتیب آرگومان های ارسال شده برای آنها نیز اساساً مهم است. آنها روش های واقعی هستند! :)

باز هم در مورد پارامترها

بله، متاسفم، ما هنوز با آنها به پایان نرسیده ایم. :) موضوعی که الان مطالعه می کنیم بسیار مهم است. 90 درصد احتمال دارد که در هر مصاحبه آینده در این مورد از شما سوال شود! بیایید در مورد انتقال آرگومان ها به روش ها صحبت کنیم. یک مثال ساده را در نظر بگیرید:
public class TimeMachine {

    public void goToFuture(int currentYear) {
        currentYear = currentYear+10;
    }

    public void goToPast(int currentYear) {
        currentYear = currentYear-10;
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        int currentYear = 2018;

        System.out.println("What year is it?");
        System.out.println(currentYear);

        timeMachine.goToPast(currentYear);
        System.out.println("How about now?");
        System.out.println(currentYear);
    }
}
ماشین زمان دو روش دارد. هر دو عدد نشان دهنده سال جاری را به عنوان ورودی می گیرند و مقدار آن را افزایش یا کاهش می دهند (بسته به اینکه بخواهیم به گذشته برویم یا آینده). اما همانطور که از خروجی کنسول می بینید، روش کار نمی کند! خروجی کنسول:
What year is it?
2018
How about now?
2018
متغیر currentYear را به متد ()goToPast ارسال کردیم ، اما مقدار آن تغییر نکرد. ما در سال 2018 بودیم و اینجا ماندیم. اما چرا؟ :/ چون primitive ها در جاوا با مقدار به متدها منتقل می شوند. معنی آن چیست؟ وقتی متد ()goToPast را فراخوانی می‌کنیم و متغیر int currentYear (2018) را به آن می‌دهیم، متد خود متغیر CurrentYear را دریافت نمی‌کند ، بلکه یک کپی از آن را دریافت می‌کند. البته مقدار این کپی نیز 2018 است، اما هر گونه تغییر در کپی به هیچ وجه بر متغیر فعلی فعلی ما تأثیر نمی گذارد! بیایید کدمان را واضح‌تر کنیم و ببینیم چه اتفاقی برای currentYear می‌افتد:
public class TimeMachine {

    public void goToFuture(int currentYear) {
        currentYear = currentYear+10;
    }

    public void goToPast(int currentYear) {
        System.out.println("The goToPast method has started running!");
        System.out.println("currentYear inside the goToPast method (at the beginning) = " + currentYear);
        currentYear = currentYear-10;
        System.out.println("currentYear inside the goToPast method (at the end) = " + currentYear);
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        int currentYear = 2018;

        System.out.println("What was the year when the program started?");
        System.out.println(currentYear);

        timeMachine.goToPast(currentYear);
        System.out.println("And what year is it now?");
        System.out.println(currentYear);
    }
}
خروجی کنسول:
What was the year when the program started?
2018
The goToPast method has started running!
currentYear inside the goToPast method (at the beginning) = 2018
currentYear inside the goToPast method (at the end) = 2008
And what year is it now?
2018
این به وضوح نشان می دهد که متغیر ارسال شده به متد ()goToPast فقط یک کپی از CurrentYear است . و تغییر کپی بر مقدار "اصلی" تأثیر نمی گذارد. «گذر از مرجع» دقیقاً برعکس است. بیایید روی گربه ها تمرین کنیم! منظورم این است که ببینیم گذر از مرجع با استفاده از مثال گربه چگونه به نظر می رسد. :)
public class Cat {

    int age;

    public Cat(int age) {
        this.age = age;
    }
}
اکنون با کمک ماشین زمان خود، Smudge را ، اولین گربه سفر زمان جهان، به گذشته و آینده می فرستیم ! بیایید کلاس TimeMachine را طوری تغییر دهیم که با اشیاء Cat کار کند.
public class TimeMachine {

    public void goToFuture(Cat cat) {
        cat.age += 10;
    }

    public void goToPast(Cat cat) {
        cat.age -= 10;
    }
}
حالا روش ها فقط عدد پاس شده را تغییر نمی دهند. در عوض، آنها زمینه سنی خاص گربه را تغییر می دهند . به یاد دارید که این برای ما با بدوی کار نمی کرد، زیرا عدد اصلی تغییر نکرد. ببینیم چی میشه!
public static void main(String[] args) {

    TimeMachine timeMachine = new TimeMachine();
    Cat smudge = new Cat(5);

    System.out.println("How old was Smudge when the program started?");
    System.out.println(smudge.age);

    timeMachine.goToFuture(smudge);
    System.out.println("How about now?");
    System.out.println(smudge.age);

    System.out.println("Holy smokes! Smudge has aged 10 years! Back up quickly!");
    timeMachine.goToPast(smudge);
    System.out.println("Did it work? Have we returned the cat to its original age?");
    System.out.println(smudge.age);
}
خروجی کنسول:
How old was Smudge when the program started running?
5
How about now?
15
Holy smokes! Smudge has aged 10 years! Back up quickly!
Did it work? Have we returned the cat to its original age?
5
وای! حالا روش کار متفاوتی انجام داد: گربه ما به شدت پیر شد، اما بعد دوباره جوان شد! :) بیایید سعی کنیم دلیل آن را بفهمیم. برخلاف مثال اولیه، هنگامی که اشیا به یک متد ارسال می شوند، توسط مرجع ارسال می شوند. یک ارجاع به شی smudge اصلی به متد ()changeAge ارسال شد . بنابراین، وقتی smudge.age را در متد تغییر می دهیم، به همان ناحیه ای از حافظه اشاره می کنیم که شی ما در آن ذخیره شده است. این اشاره به همان Smudge است که در ابتدا ایجاد کردیم. به این می گویند «گذر از مرجع»! با این حال، همه چیز با مراجع به این آسانی نیست. :) بیایید سعی کنیم مثال خود را تغییر دهیم:
public class TimeMachine {

    public void goToFuture(Cat cat) {
        cat = new Cat(cat.age);
        cat.age += 10;
    }

    public void goToPast(Cat cat) {
        cat = new Cat(cat.age);
        cat.age -= 10;
    }

    public static void main(String[] args) {
        TimeMachine timeMachine = new TimeMachine();
        Cat smudge = new Cat(5);

        System.out.println("How old was Smudge when the program started?");
        System.out.println(smudge.age);

        timeMachine.goToFuture(smudge);
        System.out.println ("Smudge went to the future! Has his age changed?");
        System.out.println(smudge.age);

        System.out.println ("And if you try going back?");
        timeMachine.goToPast(smudge);
        System.out.println(smudge.age);
    }
}
خروجی کنسول:
How old was Smudge when the program started running?
5
Smudge went to the future! Has his age changed?
5
And if you try going back?
5
بازم کار نمیکنه! О_О بیایید بفهمیم چه اتفاقی افتاده است. :) همه چیز مربوط به روش های goToPast / goToFuture و نحوه کار مراجع است. حالا، توجه شما، لطفا! این مهم ترین چیزی است که باید در مورد نحوه کار مراجع و روش ها فهمید. واقعیت این است که وقتی متد goToFuture (گربه گربه) را فرا می‌خوانیم، این یک کپی از ارجاع به شی cat است که پاس می‌شود، نه خود مرجع. بنابراین، وقتی یک شی را به یک متد ارسال می کنیم، دو مرجع به شی وجود دارد. این برای درک آنچه اتفاق می افتد بسیار مهم است. دقیقاً به همین دلیل است که سن گربه در آخرین نمونه ما تغییر نکرده است. در مثال قبلی، هنگام تغییر سن، ما به سادگی مرجع ارسال شده به متد ()goToFuture را گرفتیم و از آن برای یافتن شی در حافظه و تغییر سن آن استفاده کردیم ( cat.age += 10 ). اما اکنون، در داخل متد ()goToFuture ، ما یک شی جدید ایجاد می کنیم ( cat = new Cat(cat.age) )، و به این شی همان کپی مرجعی که به متد ارسال شده است اختصاص داده می شود. در نتیجه:
  • اولین مرجع ( لکه گربه = گربه جدید (5) ) به گربه اصلی (با سن 5 سالگی) اشاره می کند.
  • پس از آن، زمانی که متد goToPast را به متغیر cat پاس دادیم و یک شی جدید به آن اختصاص دادیم، مرجع کپی شد.
و این ما را به نتیجه نهایی رساند: دو مرجع که به دو شی متفاوت اشاره می کنند. اما ما فقط سن یکی از آنها را تغییر دادیم (یکی که در داخل روش ایجاد شده است).
cat.age += 10;
و البته در متد main() می‌توانیم روی کنسول ببینیم که سن گربه، smudge.age ، تغییر نکرده است. از این گذشته، smudge یک متغیر مرجع است که هنوز با سن ۵ سالگی به شی قدیمی و اصلی اشاره می‌کند و ما کاری با آن شی انجام ندادیم. تمام تغییرات سنی ما روی شی جدید انجام شد. بنابراین، معلوم می شود که اشیاء با مرجع به متدها منتقل می شوند. کپی از اشیا هرگز به طور خودکار ایجاد نمی شود. اگر یک شی گربه را به روشی منتقل کنید و سن آن را تغییر دهید، سن آن را تغییر خواهید داد. اما متغیرهای مرجع هنگام تخصیص مقادیر و/یا فراخوانی متدها کپی می شوند! بیایید در اینجا همان چیزی را که در مورد ارسال اولیه گفتیم تکرار کنیم: "وقتی متد changeInt() را فراخوانی می کنیم و متغیر int x (=15) را پاس می کنیم ، متد خود متغیر x را دریافت نمی کند ، بلکه یک کپی از آن را دریافت می کند. هر تغییری که در کپی ایجاد شود به هیچ وجه بر متغیر x اصلی ما تأثیر نمی گذارد ." هنگام کپی کردن مراجع، همه چیز دقیقاً به همین صورت عمل می کند! شما شی cat را به روش منتقل می کنید. اگر با خود گربه کاری انجام دهید (یعنی با شی در حافظه)، همه تغییرات شما با موفقیت اعمال می شود، زیرا ما فقط یک شی داشتیم و هنوز فقط یک شی داریم. اما، اگر یک شی جدید در داخل متد ایجاد کنید و آن را به متغیر مرجع ارسال شده به متد به عنوان آرگومان اختصاص دهید، فقط شی جدید را به یک کپی از متغیر مرجع اختصاص می دهید. از آن لحظه به بعد، دو شی و دو متغیر مرجع خواهیم داشت. خودشه! این خیلی آسان نبود حتی ممکن است مجبور شده باشید چندین بار درس را بخوانید. اما نکته مهم این است که شما به این موضوع بسیار مهم تسلط دارید. همچنان در نهایت بیش از یک بار در مورد نحوه ارسال آرگومان ها در جاوا (حتی در میان توسعه دهندگان با تجربه) بحث خواهید کرد. اما، اکنون شما دقیقاً می دانید که چگونه کار می کند. ادامه بده! :) برای تقویت آموخته هایتان، پیشنهاد می کنیم یک درس ویدیویی از دوره جاوا ما تماشا کنید
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION