به ازای هر برنامه که اجرا می‌شه یک نمونه از ماشین مجازی جاوا JVM داخل رم سیستم بارگذاری می‌شه و با استفاده از Class Loader Subsystem کلاس های مورد نظر رو وارد رم می‌کنه و بهش می‌گن dynamic class loading که کلاس‌ها رو load و link و initialize می‌کنه. البته این کار رو فقط یک بار در زمان اجرا انجام می‌ده.

  • Loading: مسئولیت اصلیش بارگذاری فایل ها توی رم هستش. در ابتدا با بارگذاری کلاس اصلی پروژه شروع می‌کنه. کلاسی که حاوی static main هستش. و بعد با توجه به دستورات کلاس های بعدی رو توی رم بارگذاری می‌کنه. سه class loader داریم که اونها از ۴ اصل پیروی می‌کنن:
  1. Visibility Principle: این اصل می‌گه که child class loader می‌تونه کلاس هایی که parent class loader بارگذاری کرده رو ببینه ولی parent class loader نمی‌تونه کلاس هایی رو که child class loader بارگذاری کردند رو پیدا کنه.
  2. Uniqueness Principle: این اصل به بارگذاری یکتا کلاس ها اشاره می‌کنه و می‌گه یک child class loader نباید بتونه کلاسی که توسط پدرش بارگذاری شده رو دوباره بارگذاری کنه. و هیچ کلاسی نباید بیش از یکبار بارگذاری بشه.
  3. Delegation Hierarchy Principle: این اصل برای اطمینان از دو اصل قبل است. JVM به صورت سلسله مراتبی کلاس ها رو بارگذاری می‌کنه و برای هر بارگذاری یک درخواست می‌فرسته. ACL درخواست رو دریافت می‌کنه و اون رو برای ECL ارسال می‌کنه و اون هم سپس درخواست رو برای BCL ارسال می‌کنه. اگر کلاس درخواست شده در Bootstrap path پیدا شد یعنی کلاس پیدا و بارگذاری شده است. در غیر این صورت درخواست برگشت داده می‌شه به ECL تا کلاس را در Extension path یا custom specific path جستجو و بارگذاری کنه. اگر این تلاش موفقیت آمیز نباشه درخواست برگشت داده می‌شه به ACL تا کلاس را در System class path جستجو و بارگذاری کنه، اگر این جستجو موفقیت آمیز نباشه ما با خطای ClassNotFoundException در زمان اجرا روبرو می‌شویم.
  4. No Unloading Principle: یک class loader می‌تونه کلاس ها رو بارگذاری کنه ولی نمی‌تونه اون رو تخلیه کنه. بجای تخلیه کلاس های بارگذاری شده ما می‌تونیم class loader رو حذف کنیم و یک class loader جدید ایجاد کنیم.
  • Bootstrap Class Loader: کلاس های استاندارد JDK و هسته جاوا را در آدرس JAVA_HOME/jre/lib بارگذاری می‌کنه. همچنین با زبان ها محلی مثلا C پیاده سازی شده و در جاوا به عنوان والد تمام class loader هاست.
  • Extension Class Loader: وظیفه داره درخواست بارگذاری را برای BCL ارسال کند و در صورت موفقیت آمیز نبودن آن را در آدرس JAVA_HOME/jre/lib/ext یا هر آدرس دیگری که در java.ext.dirs در تنظیمات سیستم قرار داره جستجو و بارگذاری می‌کنه. همچنین با زبان جاوا پیاده سازی شده و از ExtClassLoader مشتق شده است.
  • Application Class Loader: بارگذاری کلاس‌های خاص برنامه را از system class path بر عهده داره که می‌تونیم این آدرس را در زمان اجرا با فرمان cp یا classpath تغییر بدیم. به صورت پیشفرض از آدرس java.class.path استفاده می‌کنه. همچنین با زبان جاوا پیاده سازی شده و از AppClassLoader مشتق شده است.
  • علاوه بر اینها می‌توانیم با ساخت یک User-defined Class Loader در کد برنامه. کاملا مستقل کلاس ها را بارگذاری کنیم.
  • هر class loader از یک namespace استفاده می‌کنه که کلاس های بارگذاری شده خود رو در اون با روش Fully Qualified Class Name ذخیره می‌کنه. زمانی که یک class loader می‌خواهد یک کلاس را بارگذاری کنه، اون رو تو namespace خودش با روش FQCN جستجو می‌کنه. اگر اون رو پیدا کنه ولی namespace آن متفاوت باشد اون رو کلاس دیگه‌ای در نظر می‌گیره. namespace متفاوت به این معنی است که class loader دیگری این کلاس را بارگذاری کرده.
  • Linking: در این مرحله کلاس ها و اینترفیس‌های بارگذاری شده در مرحله قبل به شرط اینکه کامل لود شده باشن بررسی و آماده میشن. باید به این نکته کاملا توجه کنیم‌ که اگه توی این مرحله خطایی رخ بده، این خطا به سمت برنامه پرتاب خواهد شد. این مرحله از سه بخش زیر تشکیل شده:
  1. Verification: این سخت ترین و سنگین ترین قسمت هستش و زمان زیاری می‌بره البته بهینه هستش و فقط یک بار انجام میشه. در این مرحله مطمئن میشیم که کلاس های بارگذاری شده قواعد جاوا رو دارند و با یک کامپایلر معتبر کامپایل شدن یا نه. اگه مشکلی توی این مرحله بوجود بیاد خطای java.lang.VerifyError پرتاب می‌شه.
  2. Preparation: در این مرحله حافظه مورد نیاز کلاس‌ها شامل فضای استاتیک و فضای داده‌های کلاس به اونها تخصیص داده می‌شه. دقت کنید متغیر های استاتیک در این مرحله ساخته نمی‌شن و این کار بر عهده قسمت دیگه‌ای از برنامه‌ست.
  3. Resolution: در این مرحله نماد رفرنس داده ها با رفرنس مستقیم اونها جایگزین می‌شه.
  • Initialization: در این قسمت کلاس های بارگذاری شده ساخته می‌شوند (تابع سازنده آنها صدا زده می‌شود). این فرایند multi thread است ولی به صورت thread safe پیاده سازی شده و مانع از ساخت شدن چندباره کلاس ها می‌شود. این مرحله نهایی بارگذاری کلاس‌ها و اینترفیس‌هاست. متغیرهای استاتیک در این مرحله مقدار دهی می‌شوند و بلاک‌های استاتیک اجرا می‌شوند. به صورت سلسله مراتبی کد ما خط به خط از بالا به پایین اجرا می‌شود، در کلاس‌ها و فرزندان آنها