أساسيات جافا

ما هي Java؟ JDK وJRE وJVM

15 دقيقة الدرس 1 من 14

ما هي Java؟ JDK وJRE وJVM

تُعدّ Java واحدة من أكثر لغات البرمجة استخدامًا في العالم. إنّها تعمل في كل مكان — من هواتف Android إلى خوادم المؤسسات الخلفية، ومن الأجهزة المُدمجة إلى منصّات الحوسبة السحابية. قبل أن تكتب سطرًا واحدًا من الكود، من المفيد أن تفهم لماذا صُمِّمت Java بهذه الطريقة وكيف تعمل مكوّناتها الثلاثة الرئيسية — JDK وJRE وJVM — معًا.

لمحة تاريخية موجزة

أنشأ Java جيمس غوسلينغ وفريقه في شركة Sun Microsystems عام 1995. كان الدافع الأصلي عمليًا بشكل لافت: كانت الأجهزة الإلكترونية الاستهلاكية — كأجهزة فك تشفير التلفزيون والحواسيب الكفّية — تعمل على بنيات CPU متعددة ومختلفة. كتابة برامج منفصلة لكل رقاقة كانت مكلفة للغاية. احتاج الفريق إلى لغة تعمل برامجها المُجمَّعة على أي جهاز دون إعادة تجميع.

أطلقت Sun على Java شعارها الشهير "اكتب مرة، شغّل في كل مكان" (Write Once, Run Anywhere — WORA). هذا الوعد لا يزال في صميم Java حتى اليوم، يحافظ عليه Oracle ومجتمع OpenJDK.

إصدارات Java اليوم: منذ Java 9 (2017) تُصدر Oracle نسخة جديدة كل ستة أشهر. إصدارات الدعم طويل الأمد (LTS) — Java 11 و17 و21 — هي المستخدمة في الإنتاج. يستخدم هذا الكورس صياغة Java 17 طوال الوقت.

اكتب مرة، شغّل في كل مكان — كيف يعمل ذلك؟

معظم اللغات المُجمَّعة (كـ C وC++) تُترجم كودك المصدري مباشرة إلى كود آلة — تعليمات ثنائية لا تفهمها سوى عائلة CPU محددة. هذا يعني أنك يجب أن تُعيد التجميع لكل منصة تستهدفها.

تتّبع Java نهجًا مختلفًا. المُجمِّع لا ينتج كود آلة. بدلًا من ذلك يُنتج بايت كود — مجموعة تعليمات مضغوطة محايدة تجاه المنصة، مُخزَّنة في ملفات .class. البايت كود غير قابل للتنفيذ على أي CPU حقيقية. إنّه نوع من الوصفة التي يُفسِّرها وينفّذها برنامج خاص — الجهاز الافتراضي لـ Java (JVM) — أثناء التشغيل.

لأن JVM متاح على Windows وmacOS وLinux ومئات المنصّات الأخرى، فإن نفس ملف .class يعمل دون تغيير في كل مكان:

// Hello.java — الكود المصدري الذي تكتبه public class Hello { public static void main(String[] args) { System.out.println("Hello, Java!"); } }
// الخطوة 1: التجميع إلى بايت كود javac Hello.java // ينتج Hello.class // الخطوة 2: التشغيل على JVM java Hello // يطبع: Hello, Java!

يقرأ مُجمِّع javac ملف .java المصدري ويكتب ملف .class. يُحمِّل مُشغِّل java ملف .class إلى JVM وينفّذه. لن تتعامل مع كود الآلة أبدًا بنفسك.

البايت كود ليس بطيئًا. تتضمّن JVMs الحديثة مُجمِّع Just-In-Time (JIT) يراقب أجزاء برنامجك الأكثر تشغيلًا ويُجمِّع تلك المسارات الساخنة مباشرة إلى كود آلة أصلي أثناء التشغيل. كثيرًا ما تقترب أداء برامج Java من أداء برامج C++.

الطبقات الثلاث: JVM وJRE وJDK

هذه الاختصارات الثلاثة تُربك كل مبتدئ تقريبًا. فكّر فيها على أنّها دوائر متداخلة — كل واحدة تحتوي على ما قبلها.

1 — JVM: الجهاز الافتراضي لـ Java

الـ JVM هو المحرّك الذي ينفّذ البايت كود. وهو مسؤول عن:

  • تحميل ملفات .class عبر ClassLoader.
  • التحقّق من البايت كود للتأكد من سلامته (عدم الوصول غير المشروع للذاكرة).
  • تنفيذ التعليمات — إما بتفسيرها أو بتجميعها إلى كود أصلي (JIT).
  • إدارة الذاكرة عبر جمع القمامة — تحرير الكائنات التي لم تعد بحاجة إليها تلقائيًا.

الـ JVM بحدّ ذاته محدَّد بالمنصة (هناك ملف JVM ثنائي منفصل لـ Windows وLinux وmacOS)، لكن البايت كود الذي يشغّله عالمي.

2 — JRE: بيئة تشغيل Java

الـ JRE هو JVM مُضاف إليه مكتبة الفئات القياسية — آلاف الفئات المُدمجة المُرفقة مع Java (java.lang وjava.util وjava.io وغيرها). إذا احتاج شخص فقط إلى تشغيل تطبيق Java (لا بناؤه)، يُنصَّب JRE.

تمّ التخلّص من JRE كتنزيل مستقل في Java 11. لم تعد توزيعات Oracle وOpenJDK تُصدر JRE مستقلًا. تُثبِّت JDK وتستخدم أداة jlink لتجميع وقت تشغيل أدنى داخل تطبيقك إذا لزم الأمر. عمليًا، يُنصِّب المطوّرون دائمًا JDK.

3 — JDK: مجموعة تطوير Java

الـ JDK هو كل ما في JRE مُضافًا إليه أدوات التطوير:

  • javac — المُجمِّع الذي يحوّل الكود المصدري .java إلى بايت كود .class.
  • java — المُشغِّل الذي يبدأ JVM.
  • javadoc — يولّد توثيقًا HTML من تعليقات مُنسَّقة بطريقة خاصة.
  • jar — يُحزِّم ملفات .class في أرشيف واحد.
  • jshell — بيئة REPL تفاعلية للتجريب مع مقاطع Java.
  • مُصحِّح أخطاء، ومُحلِّل أداء، وأدوات أخرى كثيرة.

بصفتك مطوّرًا، تُنصِّب JDK دائمًا. المستخدمون النهائيون الذين يُشغِّلون تطبيقك فحسب كانوا يحتاجون سابقًا إلى JRE فقط، لكن كما ذكرنا، التوزيعات الحديثة تُدمج JRE داخل كل JDK.

تصوير العلاقة

┌─────────────────────────────────┐ │ JDK │ │ javac, jar, javadoc, jshell … │ │ ┌───────────────────────────┐ │ │ │ JRE │ │ │ │ Standard Class Library │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ JVM │ │ │ │ │ │ ClassLoader JIT │ │ │ │ │ │ GC Bytecode Eng. │ │ │ │ │ └─────────────────────┘ │ │ │ └───────────────────────────┘ │ └─────────────────────────────────┘

لماذا يهمّك هذا بصفتك مطوّرًا

فهم هذه الطبقات الثلاث يُوضِّح أشياء ستواجهها باستمرار:

  • حين يقول زميل "تأكّد من وجود إصدار Java الصحيح في PATH"، يقصد مجلّد bin/ في JDK حيث يوجد javac وjava.
  • حين تقول صورة Docker FROM eclipse-temurin:17-jre، فهي تحتوي على JRE فقط — كافٍ لتشغيل تطبيق مُجمَّع لكن ليس لبنائه.
  • حين يُسطِّر IDE import مفقودًا، مكتبة فئات JRE هي التي تُوفِّر تلك الأنواع.
  • حين يُلقي برنامج خطأ OutOfMemoryError، جامع القمامة في JVM هو الذي نفد من مساحة الكومة.
عدم تطابق الإصدارات يُسبِّب أخطاء خفيّة. إذا جمّعت ببيئة JDK 17 لكن شغّلت على JVM من Java 11، ستحصل على خطأ UnsupportedClassVersionError عند الإقلاع. تأكّد دائمًا من أن إصدار تجميعك (علامة --release) يتطابق مع إصدار JVM في الإنتاج.

الخلاصة

تحقّق Java مبدأ الكتابة مرة والتشغيل في كل مكان بتجميع الكود المصدري إلى بايت كود محايد تجاه المنصة، تُنفِّذه JVM على أي نظام تشغيل مدعوم. تُجمِّع JRE الـ JVM مع المكتبة القياسية. أما JDK فيُضيف أدوات المطوّر — وفي مقدّمتها javac — فوق JRE. في الدرس التالي ستُنصِّب JDK وتكتب أولّ برنامج Java لك وتُجمِّعه وتُشغِّله.