سلام. من از این انجمن بسیار استفاده میکنم و همیشه مشکلاتم و اینجا مطرح میکنم، و سریع هم به پاسخ میرسم. برای همین قصد دارم تا من هم برای این انجمن یک کار مفیدی انجام بدم و تا حد سواد خودم در مورد جاوا، مطالبی و قرار بدم. این مطالب آموزشهایی از مباحث مختلف جاوا است و به صورت پراکنده نوشته میشود. امیدوارم که مفید باشه.
اولین موضوع در مورد مبحث شیگرایی هست. البته قصد توضیح شی گرایی را ندارم. بلکه برای کاربران تازه کار یکسری سوءتفاهمهایی هست که میخوام به بعضی از آنها اشاره کنم.
در جاوا دو نوع داده داریم. دادههای اولیه که اصطلاحا به آنها (Primitive Data Type) میگویند و دادههای ارجاعی (Reference Data Type).
در جاوا هشت نوع دادهی اولیهی داریم که شامل: byte, short, int, long, char, float, double, boolean هستند.
کاربرد ایندادهها (به کد زیر توجه کنید):
public class MainApp {
public static void main(String[] args) {
int number = 0;
System.out.println(number);
}
}
کد فوق بسیار ساده است. یک متغیر از نوع عدد صحیح (int) تعریف کردهایم و مقدار آن را برابر با صفر قرار دادهایم و سپس آن را در خروجی استاندارد (کنسول) چاپ کردهایم. نکتهی مهمی که در مورد دادههای اولیه وجود دارد، این است که نمیتوانیم Primitive Data Typeها را اصطلاحا new کنیم و از روی آنها آبجکت (شی) ایجاد کنیم و یا نمیتوانیم بر روی آنها Dot بزنیم و یک متد یا فیلد را مورد استفاده قرار دهیم. به عنوان مثال:
number.value();
کد فوق اشتباه است و با خطای کامپایل مواجه میشویم.
اما Reference Data Typeها کدامها هستند؟ با استفاده از دادههای پایه، میتوانیم دادههای پیچیدهتر پیادهسازی کنیم. به عنوان مثال داده پایهی char، برای پیادهسازی دادهی پیچیدهتر String استفاده شده است. String یک کلاس است و جزء دادههای ارجاعی به حساب میآید. حالا اجازه دهید در مورد ارجاع صحبت کنیم:
فرض کنید یک کلاسی ایجاد کردهایم با نام Person و میخواهیم از روی این کلاس یک آبجکتی ایجاد کنیم. کد زیر:
class Person {
private String name;
}
public class MainApp {
public static void main(String[] args) {
// Object Creation OR Instantiation
Person p = new Person();
}
}
همانطور که مشاهده میکنید یک کلاسی ایجاد کردهایم با نام Person و در متد main در کلاس اصلی، کلاس Person را new کردهایم و شیئی را ساختهایم. اصطلاحا به ساخت آبجکت: Object Creation یا Instantiation گفته میشود.
سوءتفاهمی که وجود دارد این است که p
در کد فوق شی نیست، بلکه یک ارجاعی به شی است.
هنگامی که یک کلاس را new میکنیم، عملگر new در واقع دو کار را انجام میدهد. ابتدا یک شی (آبجکت) میسازد و سپس ارجاع به آن شی را بر میگرداند که ما آن ارجاع را در کد بالا در متغیر p ذخیره کردهایم. در واقع عملگر new شی را در بخشی از حافظه به نام Heap ایجاد میکند و متغیر که در کد بالا p است، در حافظهی Stack ذخیره میشود. برای درک بیشتر به عکس زیر توجه کنید:
در تصویر بالا حافظهی Heap و حافظهی Stack به صورت گرافیکی نمایش داده شده است. در هیپ آبجکتها قرار دارند و در استک رفرنسها و مقادیر دادههای پایه. همانطور که مشاهده میکنید، با یک فلش، حافظهی استک را به هیپ وصل کرده است. این به این معنا است که Referenceها یا ارجاعها هستند که از حافظهی Heap به Stack بر میگردند. عدد 32 که در استک نوشته شده است، بیانگر این است که در برنامه یک دادهی اولیه (Primitive Data Type) از نوع عدد صحیح (int) تعریف شده است.
پس نتیجهی کلی این میشود که دادههای پایه (Primitive Data Type)ها یک داده را نگه داری میکنند و دادههای ارجاعی (Reference Data Type)ها به یک شی که شامل دادههایی است اشاره میکند (ارجاعی به آن داده است).
در جاوا یک موجودی وجود دارد با نام زباله روب (Garbage Collector) که وظیفهی آن پاک سازی حافظهی Heap است. در زبانهای شی گرای دیگری مانند سی پلاس پلاس، پاکسازی آبجکتها در برنامه بر عهدهی برنامه نویس است که تا حدودی فرآیندی سخت و پیچیده است. برنامه باید به این گونه عمل کند که زمانی که در برنامه آبجکتهایی ساخته شده و از آنها استفاده شده است و دیگر مورد استفاده قرار نمیگیرند و اصطلاحا مُردهاند، باید از حافظه پاک شوند. در غیر این صورت برنامه با خطای OutOfMemoryHeapSpace مواجه میشود. یعنی حافظهی Heap پُر شده است و برنامه متوقف میشود. همانطور که گفته شد پاکسازی حافظهی Heap در زبانهایی مثل ++C بر عهدهی برنامه نویس است و این پاکسازی با افزایش آبجکتها و ارجاعات متعدد آنها با یکدیگر، بسیار سخت میشود. اما خبر خوب این است که این کار در جاوا بر عهدهی زوباله روب (Garbage Collector) است و برنامه نویس هیچ دخالتی در این کار ندارد. Garbage Collector هر از چند گاهی به حافظهی Heap سر میزند و آبجکتهای مُرده را پاک میکند و حافظه را آزاد میکند. به کد زیر توجه کنید:
public class MainApp {
public static void main(String[] args) {
String str1 = new String("Java");
String str2 = new String("C++");
str1 = str2;
}
}
در کد بالا دو آبجکت از روی کلاس String ایجاد کردهایم که هر کدام به یک قسمت خاصی از حافظه اشاره میکنند. در ادامهی برنامه، ارجاع متغیر str1 را برابر با ارجاع متغیر str2 قرار دادهایم. یعنی اینکه str1 به قسمتی از حافظه اشاره میکند که str2 دارد اشاره میکند. بنابراین چون به آبجکت Java در Heap هیچ ارجاعی وجود ندارد، این آبجکت (Java) مُرده محسوب میشود و بعدا توسط زوباله روب Garbage میشود. البته این برنامه آنقدر کم است و سریع تمام میشود که Garbage Collector اصلا وقت نمیکند اجرا شود. به هر حال کد فوق یک مثال ساده بود.
بخش اول تمام شد. امیدوارم که مفید باشد و اگر هم ایراداتی در مطلب دیدید حتما مطرح کنید