قسمت های دیگر این مطلب:

در این مطلب قصد داریم به صورت مفهومی و پله به پله با شی گرایی در جاوا آشنا شویم.

پیشتر در این مطلب به معرفی کلی شی گرایی پرداختیم. در شی گرایی هیچ مفهومی مهم تر از کلاس نیست بنابراین با ذکر مثال سعی در معرفی کلاس‌ها داریم.

اگر بخواهیم مثالی از دنیای واقعی بیان کنیم فرض کنید، خودرو می‌تواند یک کلاس باشد. در برنامه نویسی نیز می‌توان عمل خاصی را تحت عنوان یک کلاس تعریف کرد. مانند کلاس دانلود، کلاس بررسی حذف فایل و ...

هر کلاس رفتار خاصی برای خود دارد که آن را از کلاس‌های دیگر متمایز می‌سازد، مثلا کلاس خودرو با کلاس تلفن متفاوت است چون کلاس ماشین دارای حرکت است ولی کلاس تلفن دارای حرکت نیست.

اساسا کلاس‌ها را بدین منظور ایجاد می‌کنند که از آن‌ها شی‌های متنوعی بسازند مثلا از کلاس خودرو شی‌های BMW و BENZ را می‌توان داشت. می‌توان به جای شی از لفظ نمونه نیز استفاده کرد.

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

اجزای تشکیل دهنده کلاس

کلاس‌ها از دو جزء تشکیل می‌شوند: 

Variables یا متغیرها: کلاس‌ها برای عملکرد خود نیازمند متغیرهای مختلفی هستند.
Methods یا رفتارها: اعمال درون یک کلاس با متدها دسته بندی می‌شوند. البته به جای عبارت متد می‌توان از تابع نیز استفاده کرد.

کلاس Car را در پایین ببینید:

public class Car {
    private String kilometers;
    public String brake_type(){
        String brake= "ABS";
        return brake;
    }
    public int Speed(){
        int max_speed= 180;
        return max_speed;
    }
}

نکته: اگر با برخی واژه‌ها آشنا نیستید نگران نباشید و در ادامه همه توضیح داده می‌شوند.

سطر اول: کلمه کلیدی public سطح دسترسی کلاس، کلمه کلیدی class برای مشخص کردن کلاس و Car نام کلاس است.

سطر دوم: یک متغیر با سطح دسترسی private از نوع String و با نام kilometers.

سطر سوم: یک متد تعریف شده است که public سطح دسترسی این متد، String نوع خروجی و brake_type نام این متد است. پرانتز باز و بسته شده بعد از brake_type ضروری است و برای ورودی‌های متد است.

سطر چهارم: یک متغیر از نوع String و با نام brake ایجاد کردیم.

سطر پنجم: در سطر سوم گفتیم متد brake_type یک خروجی از جنس String دارد بنابراین مقدار return شده تابع از جنس String است.

سطر هفتم: متدی با سطح دسترسی public و خروجی int و با نام speed.

سطر هشتم: متغیری با نام max_speed و از نوع int و با مقدار اولیه 180.

سطر نهم: خروجی return شده از نوع int برای اتمام کار تابع.

متد یا تابع چیست

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

برخی متدها ورودی دارند که این ورودی‌ها باید درون پرانتزهای بعد از نام تابع ذکر شوند. کلاس زیر را ببینید:

public class Car {
    private String kilometers;
    String brake= "ABS";
    
    public String brake_type(String brake){
        return brake;
    }
    public int Speed(){
        int max_speed= 180;
        return max_speed;
    }
}

در مثال بالا و در سطر سوم یک متغیر به نام brake می‌بینید که در سطر پنج به عنوان ورودی به تابع brake_type داده شده است و در سطر ششم به عنوان خروجی پس از return قرار گرفته است.

چرا باید از توابع در برنامه نویسی استفاده کنیم

سوال فوق پاسخ‌های بسیاری دارد. وقتی از متدها استفاده می‌کنید فرایند مدیریت برنامه ساده تر می‌شود. فرض کنید در برنامه شما ده بار قرار است اتصال به wifi چک شود و در صورت وصل نبودن کاربر به wifi پیام مناسب برای او نمایش داده شود.

حال تصور کنید هر یک بار از این ده بار باید پنج سطر کد برای این کار بنویسید، این یعنی 50 سطر کد تنها برای بررسی متصل بودن یا نبودن به wifi و نمایش پیام در صورت لزوم نیاز دارید.

برای عملیات مذکور یک متد می‌نویسیم و هر کجا به آن نیاز داشتیم تنها اسم این متد را به کار می‌بریم تا برنامه با مراجعه به متد عملیات لازم را انجام دهد.

حال فرض کنید در برنامه خود از روش مذکور استفاده نکردید و بدون متد در 10 جای برنامه عملیات بررسی وصل بودن به wifi را انجام دادید. پس از مدتی تصمیم گرفتید الگوریتم بررسی اتصال به wifi را کمی تغییر دهید، باید این تغییر در همه جای برنامه انجام پذیرد، و شاید اگر یک جا را فراموش کنید کل برنامه با مشکل مواجه شود. پس با استفاده از متد‌ها حتی رفع عیب از برنامه بسیار ساده می‌شود.

انواع متغیر‌های استفاده شده در کلاس ها

اساسا سه نوع متغیر درون کلاس‌ها می‌توان تعریف کرد. اولین نوع متغیر که در بالا نیز به آن اشاره کردیم Local Variable است که درون متدهای کلاس استفاده می‌شود. این متغیرها تنها درون متد اعتبار دارند و خارج متد کاربردی ندارند.

دومین نوع متغیر عبارت است از Instance Variable که خارج متد‌ها تعریف می‌شود و در هر شی و یا نمونه از کلاس قابل تغییر است. مثلا حجم موتور می‌تواند برای ماشین‌های متنوع متفاوت باشد.

سومین نوع متغیرClass Variable یا متغیر کلاسی نام دارد نیز خارج متدها تعریف می‌شود و در تمام نمونه‌های کلاس غیر قابل تغییر است. برای ایجاد این متغیر‌ها از کلمه کلیدی static استفاده می‌شود.

در مثال زیر سه نوع متغیر فوق دیده می‌شوند:

public class Car {
    private static String kilometers;
    public String brake= "ABS";

    public String brake_type(String brake){
        return brake;
    }
    public int Speed(){
        int max_speed= 180;
        return max_speed;
    }
}

در سطر دوم یک متغیر با نام kilometers و با سطح دسترسی private و نوع static ایجاد شده است که نشانگر این است که متغیر kilometers از نوع متغیرهای کلاسی است. دو علامت یک متغیر کلاسی قرار گرفتن خارج از متدها و داشتن کلمه کلیدی static است.

در سطر سوم یک متغیر از نوع Instance می‌بینید. متدهای Instance خارج متدها قرار می‌گیرند و کلمه کلیدی static را در تعریف خود ندارند.

در سطر نهم نیز یک متغیر از نوع Local  داریم که درون متد قرار دارد.

قبل از پرداختن به ادامه مبحث مفهوم با مفهوم پکیج‌ها در جاوا آشنا شوید:

مفهوم Package ها

پکیج‌ها برای تفکیک کلاس‌ها کاربرد فراوانی دارند و به منظور جلوگیری از تداخل نام کلاس‌ها استفاده می‌شوند. اگر به کلاس‌های پروژه اندروید خود خوب نگاه کرده باشید در اولین سطر نام پکیج کلاس درج شده است:

پکیج‌ها در جاوا و برنامه نویسی اندروید

در جاوا می‌توان به منظور مرتب تر کردن پروژه کلاس‌ها را در پکیج‌های مختلفی تقسیم کرد. مثلا پکیجی برای کلاس‌های مرتبط با پایگاه داده، پکیجی برای کلاس‌های مرتبط با API‌ها و ...

مثلا پکیج برنامه فوق ir.hitos.hitos نام دارد و می‌توان پکیج‌های دیگری نیز به آن افزود.

برای اضافه کردن یک Package تازه دو راه کار دارید، ابتدا به مسیر پروژه اندروید رفته و از آن پوشه‌های زیر را پیمایش کنید:

app -> src -> main -> java

در مسیر جاری هر پوشه‌ای که ایجاد کنید تبدیل به یک Package می‌شود.

به پوشه موجود در مسیر فوق رفته و پوشه‌ها را پیمایش کنید، خواهید دید هر پوشه یک جزء از نام Package اصلا پروژه شماست. مثلا پروژه‌ای که برای این آموزش ایجاد شده ir.hitos.hitos نام دارد یعنی سه پوشه درون هم با نام‌های ir و hitos و hitos داریم.

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

یک راه دیگر برای ساخت پکیج جدید این است که از منو File گزینه New و سپس Package را انتخاب کنید. از پنجره باز شده گزینه ..\app\src\main\java را انتخاب کنید. نام پکیج جدید را در پنجره وارد کرده و Ok را انتخاب کنید.

ساخت یک نمونه یا شیء در جاوا

همانطور که در شروع این مبحث گفتیم در جاوا از هر کلاس باید بتوان اشیاء یا نمونه‌های مختلفی ایجاد کرد. به عنوان مثال یک کلاس با نام Car در کنار کلاس MainActivity پروژه ایجاد می‌کنیم.

سورس کلاس Car به شرح زیر است:

package ir.hitos.hitos;

public class Car {
    public static String kilometers;
    protected String brake= "ABS";

    public String brake_type(String brake){
        return brake;
    }
    public int Speed(){
        int max_speed= 180;
        return max_speed;
    }
}

درون کلاس MainActivity پروژه اندروید یک شی از کلاس Car به شکل زیر ایجاد می‌کنیم.

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

Class_Name Object_Name= new Class_name();

به جای Class_name نام کلاس و به جای object_Name نام شی جدید را وارد می‌کنیم.

به عنوان مثال از کلاس Car چند نمونه ماشین ایجاد می‌کنیم:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Car Pride = new Car();
        Car Peugeot = new Car();
    }
}

در سطرهای هشت و نه دو شی به نام‌های Pride و Peugeot از کلاس Car ایجاد می‌کنیم.

برای استفاده از متدها و یا متغیرهای کلاس‌های دیگر پس از ایجاد شی از کاراکتر نقطه استفاده کرده و نام متد را ذکر می‌کنیم. مانند:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Car Peugeot = new Car();
        Peugeot.Speed();
        Peugeot.brake_type("ABS");
    }
}

سطر 8: در این سطر یک شی جدید به نام Peugeot از کلاس Car ایجاد کردیم.

سطر 9: در این سطر متد Speed را از کلاس Car فراخوانی کردیم.

سطر 10: در این سطر متد brake_type را از کلاس Car فراخوانی کردیم. اگر به کلاس Car توجه کنید خواهید دید متد brake_type یک ورودی از جنس String دارد بنابراین به این متد در اینجا نیز ورودی از نوع String دادیم

سطوح دسترسی در جاوا

در مطالب پاراگراف‌های قبلی گفتیم از کلمه‌های کلیدی public و یا private برای تعیین سطح دسترسی کلاس ها، متد‌ها و یا متغیرها استفاده می‌کنیم. اساسا چهار سطح دسترسی در جاوا وجود دارد که عبارتند از:

سطح دسترسی default: تنها در کلاس‌های Package جاری قابل دسترس هستند. در ساب کلاس‌ها و یا کلاس‌های فرزند پکیج‌های دیگر قابل دسترس نیستند. (با مفهوم کلاس‌های فرزند یا ساب کلاس‌ها در ادامه آشنا خواهید شد).

سطح دسترسی public: در همه جا قابل دسترس هستند.

سطح دسترسی private: فقط در همان کلاس قابل دسترس هستند.

سطح دسترسی protected: فقط برای پکیج جاری و در کلاس‌های فرزند یا ساب کلاس‌ها قابل دسترس هستند.

سطح دسترسی کلاس‌ها را در ادامه با هم بیشتر می‌شناسیم. به عنوان مثال سورس کلاس Car را به شکل زیر ویرایش کنید:

package ir.hitos.hitos;

public class Car {
    public static String public_static_string;
    private String private_string;
    protected String protected_string;
    String default_string;
}

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

نکته 2: اساسا سطح دسترسی default نیازی به کلمه کلیدی ندارد و همانطور که در سطر هفت می‌بینید این متغیر را بدون نیاز به نوشتن default قبل از String ایجاد می‌کنیم.

کلاس MainActivity را مانند زیر ویرایش کنید:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Car Peugeot = new Car();
        String str1 = Peugeot.public_static_string;
        String str2 = Peugeot.protected_string;
        String str3 = Peugeot.default_string;
    }
}

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

سطر 7: شی Peugeot را با استفاده از کلاس Car ایجاد کردیم.

سطر 8: در این سطر متغیر با نام public_static_string را از شی Peugeout گرفته و درون متغیر str1 که از نوع String است قرار دادیم.

سطر 9: متغیر با نام protected_string را از شی Peugeout گرفته و درون متغیر str2 قرار دادیم.

سطر 10: متغیر با نام default_string را از شی Peugeout گرفته و درون متغیر str3 قرار دادیم.

اگر نتایج فوق را به خوبی دیده باشید خواهید دید که نمی‌توانیم متغیر private_string را درون این کلاس فراخوانی کنیم چون این متغیر از نوع private می‌باشد.

برای بررسی عملکرد سطوح دسترسی در پکیج‌های دیگر یک پکیج در کنار Package اصلی برنامه با نام test.hitos ایجاد کرده و یک کلاس به نام Test در آن ایجاد کنید. نتیجه را در تصویر زیر ببینید:

ایجاد پکیج برای آموزش شی گرایی و oop در برنامه نویسی جاوا و اندروید

در کلاس Test یک شی به نام BMW از روی کلاس Car ایجاد کنید و ببینید چه متدها و متغیرهایی قابل دسترس هستند:

package test.hitos;
import ir.hitos.hitos.Car;

public class Test {
    Car BMW = new Car();
    String str1 = BMW.public_static_string;
}

همانطور که در سطر 6 می‌بینید تنها امکان استفاده از متغیر public در این جا وجود دارد.

فراخوانی متدها و متغیرهای static بدون نیاز به ایجاد شی جدید

در اول این مبحث گفتیم برای تعریف Class Variable یا متغیر کلاس باید پس از ذکر سطح دسترسی متغیر از کلمه کلیدی static استفاده کنید. این قضیه در مورد متد‌ها نیز صادق است. کلاس Car را در زیر ببینید:

package ir.hitos.hitos;

public class Car {
    public static String public_static_string;

    public static String brake(){
        return "ABS";
    }
}

نکته جالبی که در مورد متغیرهای static وجود دارد این است که برای استفاده از آن‌ها نیازی نیست حتما یک شی جدید ایجاد کنید. کلاس Car قبلی را در نظر بگیرید، کلاس MainActivity را مانند زیر ویرایش می‌کنیم:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String str = Car.public_static_string;
        Car.brake();
    }
}

در سطر 8 بدون نیاز به تعریف شی جدید از کلاس Car، به سادگی و تنها با ذکر نام کلاس Car و پس از آن ذکر نام متغیر static از آن استفاده کردیم.

در سطر 9 نیز بدون نیاز به ایجاد شی جدید از متد brake استفاده کردیم.

مفهوم Modifier‌ها در شی گرایی

Modifier‌ها کلمه‌های کلیدی‌ای هستند که سطح دسترسی و نوع استفاده از متغیرها و متد‌ها را مشخص می‌کنند. اساسا Modifier‌ها بر دو نوع هستند، که در زیر به این دو نوع اشاره می‌کنیم:

1- Access Modifiers که مربوط به دسترسی هستند. سه کلمه کلیدی public و private و protected تشکیل دهنده این Modifier‌ها هستند.

2- Non-Access Modifiers که ارتباطی به سطح دسترسی ندارند و وظایف دیگری دارند. سه کلمه کلیدی static و final و abstract نیز تشکیل دهنده این نوع از Modifier‌ها هستند.

در این قسمت به صورت اجمالی به Access Modifiers‌ها اشاره کردیم، در قسمت بعدی نیز مبحث آن‌ها را ادامه می‌دهیم.

اما Non-Access Modifiers‌ها به شرح زیر هستند:

static: همانطور که در پاراگراف‌های قبلی گفتیم، متد و یا متغیری که از نوع static تعریف شود برای استفاده نیازی به ایجاد یک شی جدید ندارد.

final: متد و یا متغیری که از این نوع باشد غیر قابل ویرایش و تغییر است.

abstract: توضیح این Modifier کمی پیچیده است ولی به صورت اجمالی وقتی از آن استفاده می‌کنیم که بدانیم چه کارهایی را باید انجام بدهیم ولی مراحل عمل را حین ایجاد کردن شی جدید تعریف کنیم. در قسمت بعدی این Modifier را به صورت تفصیلی معرفی می‌کنیم.

قسمت بعدی را برای تکمیل این مبحث از دست ندهید.