آموزش برنامه نویسی جاوا (بخش هجدهم: کار با متدها در جاوا – قسمت دوم)

استاندارد

در بخش قبلی، کار با متدها توضیح داده شد. تقریبا بیشتر برنامه های سطح متوسطی که در ادامه خواهیم نوشت، با همان معلومات کافی خواهند بود. ولی بعضی اوقات حتی در یک برنامه ی ساده نیز ممکن است کمی کار پیچیده شود.

در این بخش به ادامه ی مباحثی در مورد کار با متدها می پردازیم. تا کار با متدها را تقریبا تمام کنیم.

این که می گوییم “تقریبا” ، بدان معنی ست که مباحثی تکمیلی در مورد متدها لازم است در آینده مطرح شود که احتیاج است مطالبی دیگر را ابتدا بلد باشید.

آرگومان های متغیر(Variable Arguments)

در بخش قبلی توضیح دادیم که اگر بخواهیم تعداد ورودی های مختلفی به تابع بدهیم باید از مفهوم Overload برای توابع استفاده نماییم.

از JDK 1.5 به بعد می توانیم توسط مفهوم Variable Arguments ، هر تعداد پارامتر ورودی از یک نوع که می خواهیم به تابع بدهیم.

این نوع ورودی ها آرگومان های متغیر نام دارد که به شکل زیر تعریف می شود.

typeName... parameterName

برای تعریف این گونه پارامترها در تابع، باید نوع متغیر را ابتدا مشخص کنید سپس از سه نقطه (…) بدون فاصله از نوع متغیر استفاده نمایید.

در مرحله ی بعد، نامی دلخواه برای پارامتر دریافتی در مقصد نیز مشخص کنید.

مثال:

public class JavaApplication1 {

    public static void main(String[] args) {

        int a = 1;
        int b = 2;
        int c = 3;
        int d = 4;
        VAMethod(a,b,c,d);

    }
    public static void VAMethod(int... numbers){
       System.out.print(numbers.length); // numbers نمایش طول متغیر آرایه ای 
       System.out.print(numbers[2]); // numbers نمایش خانه ای از آرایه ی
    }   
}

همان طور که در بالا مشاهده می نمایید، numbers یک متغیر آرایه است. و با آن به همان صورتی که با آرایه برخورد می کنیم.

متد finalize

بعضی اوقات در جاوا این امکان وجود دارد که در هنگام از بین رفتن یک شی، عمل خاصی انجام شود.

از بین رفتن شی یعنی این که آن شی از داخل حافظه پاک شود.

عمل خاص می تواند، این گونه باشد که قبل از ، از بین رفتن شی ، عملیاتی همچون بستن فایل ها و یا ارتباطات دیتابیس انجام شود.

این عمل در جاوا توسط متد finalize انجام می شود.

همه ی عملیاتی که می خواهیم در هنگام بسته شدن شی انجام شود باید در متد finalize تعریف شود.

finalize به شکل کلی زیر است:

protected void finalize( )
{
   //  finalize کدهای 
}

اگر دقت کنید متوجه می شوید که modifier این متد، از نوع protected تعریف شده است.

دلیل این کار این است که کسی نتواند از خارج از شئ به این متد دسترسی داشته باشد و نتواند آن را صدا بزند.

آموزش برنامه نویسی جاوا (بخش هفدهم: کار با متدها در جاوا)

استاندارد

در بخش قبل با متدها در زبان برنامه نویسی جاوا ، آشنا شدیم. همچنین در مورد اجزای متدها و کمی در مورد نحوه عملکرد آن ها توضیح داده شد.

در این بخش با فراخوانی متدها در توابع مختلف آشنا خواهیم شد.

فراخوانی متدها

برای فراخوانی یک متد باید آن را در جای دیگری صدا بزنیم. زمانی که یک متد صدا زده می شود، کامپایلر، به سراغ اجرای کدهای تعریف شده برای آن متد می رود.

برای فراخوانی یک متد، دو راه وجود دارد:

1- زمانی که متد هیچ مقداری را بر نمی گرداند: در این نوع صدا زدن کافی ست، اسم متد را در تابع اصلی یا هر تابع دیگری که می خواهیم، بنویسیم. سپس در داخل پرانتز لیست آرگومان های ورودی آن متد را در صورت وجود بنویسیم. سپس در آخر از علامت “;” استفاده می کنیم.

وقتی کامپایلر به این خط از برنامه می رسد، کدهای داخل بدنه ی متد فراخوانی شده را اجرا می کند. سپس به ادامه ی کدهای تابعی که در آن بوده است، می پردازد.

به عنوان مثالی از این نوع فراخوانی، کد زیر را مشاهده نمایید:

public class JavaApplication1 {

    public static void main(String[] args) {
        ShowMessage(); // فرخوانی متد
    }
    // تعریف متد
    static void ShowMessage(){
        System.out.print(("Gsm Developers")); // چاپ خروجی
    } 
}

در کد بالا وقتی تابع main اجرا می شود، به سراغ متد و کدهای بدنه ی ShowMessage می رود. در بدنه ی متد ShowMessage نیز، رشته ی “Gsm Developers” چاپ می شود. پس خروجی کد بالا نیز Gsm Developers است.

2- زمانی که متد، مقداری را بر می گرداند: در این نوع صدا زدن، نمی توان فقط با نوشتن اسم متد، آن را صدا زد. زیرا متد مقداری را بر می گرداند و از آن مقدار باید در جایی استفاده شود. مثلا ذخیره شود و یا به عنوان خروجی چاپ شود و …

به عنوان مثال، کد زیر متدی را صدا می زند که مقدار برگشتی دارد:

public class JavaApplication1 {

    public static void main(String[] args) {
        float m = divide(5,6); // m فراخوانی تابع و ریختن مقدار برگشتی آن در متغیر
        System.out.print(m); // m چاپ متغیر 
    }
    //تابع تقسیم
    static float divide(float num1 , float num2){
        float z = num1 / num2;
        return z; // مقدار برگشتی
    }
}

در کد بالا ، بعد از آن که تابع main اجرا شد، به سراغ متد divide می رود. سپس بعد از اجرای کدهای متد divide ، مقدار خروجی متد divide به متغیر m ریخته می شود.

دقت کنید، از آنجایی که در کد بالا تابع main خود به صورت static تعریف شده است، پس هر تابعی که در داخل آن فراخوانی می کنیم باید به صورت static تعریف شود.

همچنین می توانید در داخل متودی، متود دیگری نیز فرخوانی نمایید که به همین شیوه انجام می شود. و فقط کافیست کدهای آن متد در کلاس مربوطه، تعریف شده باشند.

overload کردن متدها

در جاوا همان طور که دیدید، با استفاده از اسم یک متد می توان آن را فراخوانی نمود. اسم متد، همان اسمی است که در هنگام ساخت برای آن تعریف کردیم.

ولی آیا نمی توان با همین اسم، متدی با بدنه و ساختاری دیگر تعریف کرد؟

در جاوا پیش می آید که بخواهیم از این روش استفاده کنیم. زیرا گاهی پیش می آید که بخواهیم متدها را با پارامترهای مختلفی فراخوانی کنیم.

مثلا بخواهیم متد مورد نظر ما، یک بار بدون پارامتر فراخوانی شود و یک بار با پارامتر String و یک بار با پارامتر int. ولی ما فقط یک پارامتر می خواهیم به آن متد ارسال نماییم ، نه بیشتر.

تعریف دو متد با نام یکسان و نوع خروجی و متغیر های یکسان باعث خطا می شود.

به این گونه تعریف متد ها با نام یکسان ولی پارامترهای متفاوت overload کردن متدها یا method overloading گفته می شود.

به عنوان مثال، به کد زیر خوب دقت کنید:

public class JavaApplication1 {

    public static void main(String[] args) {
        ShowMessage(); // تابع اول
        ShowMessage("Gsm Developers 2"); // تابع دوم

    }
    // تابع اول
    static void ShowMessage(){
        System.out.print(("Gsm Developers 1\n"));
    }
    // تابع دوم
    static void ShowMessage(String message){
        System.out.print(message);
    }
}

خروجی کد بالا به صورت زیر است:

Gsm Developers 1

Gsm Developers 2

اولین ShowMessage ی که در کد بالا در تابع اصلی main فراخوانی شد، بدون پارامتر است. پس تابع اولی که مشاهده می کنید، فراخوانی می شود.

ولی تابع دومی که در main فراخوانی می کنیم، بدنه ی تابع دومی که متغیر message به عنوان پارامتر ارسالی، تعریف شده است، فراخوانی می شود.

آموزش برنامه نویسی جاوا (بخش شانزدهم: معرفی متد در جاوا)

استاندارد

این بخش به بررسی یکی از مفاهیم اصلی در هر زبان برنامه نویسی ، یعنی متدها می پردازد. در واقع در فصول قبل، ما مقداری از الزامات و مقدمات برنامه نویسی را یاد گرفتیم و تا کنون برنامه خاصی ننوشتیم.

وقتی خطوط برنامه ما زیاد می شود درک، پیگیری، خطایابی و دیگر اعمال بر روی برنامه دشوار خواهد شد. توابع ابزاری هستند که به ما در بهبود برنامه کمک می کنند و برنامه نویسی ساخت یافته را ارائه می دهند، بدین معنا که برنامه اصلی به قسمتهای منطقی و مستقل کوچکتری تقسیم می شود که توابع نام دارند.

نام دیگر متد، تابع است. یک تابع لیستی از دستورات را در خود دارد که با فراخوانی آن، این دستورات اجرا می شوند.

 

برای بکارگیری توابع به سه جزء نیازمندیم: تعریف تابع، اعلان تابع، فراخوانی تابع

می توانید شکل کلی از تعریف یک متد (تابع) را به همراه اجزای آن، در زیر مشاهده می کنید:

هر بار که ما کدهای جاوا را در بخش های قبلی کامپایل می کردیم، تابع اصلی Main این کار را برای ما انجام می داد.

به بررسی متد main در جاوا می پردازیم. در زیر مشاهده می کنید که ابتدا یک کلمه ی کلیدی به نام public آورده شده است. این کلمه یک Modifier است که در بخش پانزدهم به آن پرداختیم. کلمه کلیدی public و باعث می شود که به این متود بتوان در کل برنامه دسترسی داشت.

public static void main(String[] args) {
// کدهای اصلی برنامه
}

سپس کلمه void آورده شده است که باعث می شود این متود چیزی را به عنوان بازگشتی ارسال نکند.

در ادامه متدهای دیگری معرفی می شود که می توانند هر نوع داده ای و حتی کلاس را به عنوان مقدار بازگشتی داشته باشند.

بعد از کلمه کلیدی Modifier ، نام متد آورده شده است. در اینجا نام متد main است.

سپس در داخل پرانتز، آرگومان ورودی این تابع ( یعنی String[] args ) آورده شده است.

برای تعریف بدنه اصلی یک تابع، کدهای برنامه را در داخل بلاک {} می نویسند.

نوع تابع (مثلا Void) ، نام تابع به همراه پرانتز و بلاک ، حداقل مواردی هستند که باید در کدهایمان برای تعریف یک تابع بنویسیم.

مثلا تابع زیر، شامل این حداقل موارد است:

void myMethod(){
        //بدنه تابع
}

گفته شد که هر متد می تواند مانند متغیر، انواع داده ای مختلف را برگرداند. در بالا Void معرفی شد. Void مقداری را به عنوان خروجی برنمیگرداند. ولی اگر متد ما، Void نباشد، پس حتما باید یک نوع داده ای را به عنوان خروجی برگرداند.

این نوع خروجی می تواند یک داده ی عددی صحیح (int) ، یک داده عددی اعشار (float ) ، یک رشته (String) و یا از نوع Boolean) Bool) و … باشد.

ولی حتما دقت داشته باشید که اگر متد شما Void نباشد، حتما باید از دستور return برای برگرداندن مقدار مورد نظر، استفاده کنید.

مثلا تابع زیر باعث ایجاد خطا می شود:

int myMethod(){
}

پس باید به شکل زیر اصلاح شود:

int myMethod(){
    return 0;
}

مشاهده می کنید که تابع بالا، عدد 0 را برای شما به صورت خروجی برمی گرداند.

حال اگر مقدار خروجی تابع شما از نوع رشته (String) باشد، باید در جایی از بدنه، باید کد return مقداری به صورت String برگرداند:

String myMethod(){
       return "Gsm";
}

می توان یک ساختمان داده (آرایه و…) و یا یک کلاس را نیز به عنوان خروجی تابع برگرداند.

مثلا متد زیر از نوع آرایه ی کاراکتری تعریف شده است که مقدار myChars را به صورت خروجی برمیگرداند:

char[] myMethod(){
       char[] myChars = {'A','B','C'};
       return myChars;
}

ارسال پارامتر به متد

قسمت بعدی که می خواهیم به آن بپردازیم، آرگومان های ورودی تابع است که در پرانتز نوشته می شوند. اگر بخواهید مقادیر و یا متغیرهایی را به تابع ارسال نمایید چه کار می کنید؟

یک راه اینست که متغیر را به صورت Public تعریف کنید و در داخل تابع، عملیات مورد نظر را بر روی آن انجام دهید. ولی هر تغییری بر روی این متغیر در هر جای تابع، مقدار این متغیر را به کل عوض می کند.

ولی ما نمیخواهیم این کار انجام شود.

مثال دیگری که به آن می پردازیم در ریاضی به آن برخورده اید.

اگر در ریاضی به یاد داشته باشید، تابع y=x+2 ، یعنی y بر حسب x تعریف می شود. پس اگر به عنوان مقدار ورودی به x ، عدد 3 را بدهیم، مقدار y برابر 5 می شود. عدد 3 در اینجا یک پارامتر و آرگومان ارسالی به این تابع است.

در واقع با استفاده از این آرگومان ها می توان پارامترهایی را به تابع ، ارسال نمود.

فرض کنید بخواهید تابعی برای عمل تقسیم بنویسید. برای این کار به دو عدد احتیاج است. حال تابع شما، در لیست پارامترهای خود این دو عدد را دریافت می کند سپس یکی از آن اعداد را بر دیگری تقسیم می کند و نتیجه را به صورت int و یا float بر می گرداند.

جایگاه این پارامترها در تعریف تابع کجاست؟

بار دیگر به این شکل نگاه کنید:

 

پس از آن که نوع تابع را مشخص کردیم، نامی دلخواه برای تابع تعیین می کنیم. سپس در قسمت پرانتز ها، می توانید لیست پارامترها و یا آرگومان های ورودی تابع را مشخص کنید.

برای تعریف لیست پارامترها، ابتدا نوع متغیر و سپس نامی دلخواه برای متغیر، درنظر می گیریم. اگر از بیش از یک متغیر استفاده نمودیم، باید آن ها را با ” , ” از هم جدا کنیم.

در واقع شبیه تعریف نمودن یک متغیر است با این تفاوت که پس از تعریف از ” ; ” در آخر هیچ کدام از متعیر ها و پارامترهای داخل پرانتز، استفاده نمی کنیم.

به عنوان مثال می توانید کد زیر را که عمل تقسیم انجام می دهد، مشاهده کنید. این تابع دارای دو پارامتر ورودی است.

static float divide(float num1 , float num2){
        float z = num1 / num2;
        return z;
}

در کد بالا، در داخل پرانتز دو متغیر num1 و num2 از نوع float تعریف شده اند. سپس این تابع در داخل بدنه ی خود، بر روی این دو متغیر عمل تقسیم را انجام می دهد. ( پارامتر اول (num1) بر روی پارامتر دوم(num2) تقسیم می شود) .

سپس نتیجه به عنوان بازگشتی به تابع برگردانده می شود.

پارامترهایی که هنگام فراخوانی به متد داده می شوند باید به همان ترتیبی باشند که در تعریف متد آورده شده اند و همچنین نوع آنها نیز باید به همان شکل باشد. وقتی که یک پارامتر به متد ارسال می شود دوحالت عمده ممکن است پیش بیاید.

  • هر تغییری که در بدنه متد بر روی پارامتر انجام می دهیم در خارج از متد نیز آن تغییرات اعمال شوند
  • هر تغییر که در بدنه متد برروی پارامترها انجام می دهیم در خارج از متد آن تغییرات بی تاثیر می باشند.

نوع اول ارجاع با استفاده از آدرس متغیر، و نوع دوم ارسال پارامتر با استفاده از مقدار است.

در بخش بعدی که فراخوانی متدها را نیز آموزش می دهیم، با این دو بیشتر آشنا می شویم.