صرّف أولًا، ثم شغّل
الآن وقد ثبّتّ JDK، صار تشغيل Java دورةً من خطوتين. على عكس لغات السكربتات حيث توجّه المُفسِّر إلى ملف فينطلق، تقوم Java أولًا بـتصريف مصدرك القابل للقراءة البشرية إلى بايت كود، ثم تأتي خطوة منفصلة لـتشغيل ذلك البايت كود على آلة JVM.
تقابل هاتان الخطوتان أداتين من أدوات سطر الأوامر تأتيان مع JDK:
javac- المُصرِّف. يقرأMain.javaويكتبMain.class(بايت كود).java- المُشغِّل. يبدأ آلة JVM وينفّذ البايت كود الموجود فيMain.class.
يمكنك تشغيل أي مثال مكتفٍ بذاته هنا على الصفحة مباشرةً - فالمحرر بالأسفل ينفّذ الخطوتين نيابةً عنك. لكن يستحق الأمر أن تفهم ما يجري على جهازك الخاص، لأن المشاريع الحقيقية تعيش هناك.
الأمران على جهازك
لنفترض أن لديك هذه الشيفرة محفوظة باسم Main.java:
public class Main {
public static void main(String[] args) {
System.out.println("Hello from the terminal");
}
}
افتح طرفية في المجلد الذي يحتوي على الملف، وشغّل المُصرِّف:
javac Main.java
إذا صُرِّفت الشيفرة دون أخطاء، فلن يطبع javac شيئًا وسينشئ ملفًا جديدًا، Main.class، بجوار مصدرك. ذلك الملف .class هو البايت كود - وهو ليس نصًّا قابلًا للقراءة، وليس مرتبطًا بنظام تشغيلك.
والآن شغّله بأمر java:
java Main
Hello from the terminal
أكثر أخطاء المبتدئين شيوعًا هنا: تشغّل java، لا javac، لتشغيل البرنامج، وتمرّر اسم الصنف بلا امتداد. الصحيح هو java Main - وليس أبدًا java Main.class ولا java Main.java.
يجب أن يطابق اسم الملف اسم الصنف العام
تفرض Java قاعدةً تفاجئ القادمين الجدد: يجب أن يقيم الصنف public في ملف يحمل الاسم نفسه تمامًا، مضافًا إليه .java. فالصنف public class Main يجب أن يكون في Main.java. أخطئ في حالة الأحرف، يرفض javac التصريف.
// This is in a file called Greeting.java
public class Greeting { // ERROR: class Greeting should be in Greeting.java... wait, it is
public static void main(String[] args) {
System.out.println("Hi");
}
}
أما عدم التطابق الذي يربك الناس فعلًا فهو أدق - تسمية الملف greeting.java (بأحرف صغيرة) بينما الصنف هو Greeting، أو حفظ Main.java لكن كتابة public class Hello. يبلّغ المُصرِّف بشيء مثل:
Main.java:1: error: class Hello is public, should be declared in a file named Hello.java
الحل دائمًا هو ذاته: اجعل اسم الملف واسم الصنف العام متطابقين، حرفًا بحرف.
الاختصار: تشغيل ملف واحد مباشرةً
منذ JDK 11، يمكنك تخطي خطوة التصريف الصريحة لملف مصدري واحد. سيصرّفه أمر java في الذاكرة ويشغّله دفعةً واحدة - دون كتابة أي ملف .class على القرص:
java Main.java
هذا مثالي للتجارب السريعة والسكربتات الصغيرة. لاحظ الفرق فيما تمرّره:
java Main- يشغّل ملفMain.classمُصرَّفًا مسبقًا.java Main.java- يصرّف الملف المصدري ويشغّله دفعةً واحدة.
لا يعمل وضع الملف الواحد إلا حين يتسع برنامجك بأكمله في ملف واحد. وفي اللحظة التي تقسّم فيها الشيفرة عبر أصناف عدة في ملفات عدة، تعود إلى التصريف بـjavac أولًا. ولتعلّم الأساسيات، يبقي وضع الملف الواحد الدورة قصيرة.
تمرير الوسائط إلى برنامجك
أتتذكر String[] args في main؟ تلك هي وسائط سطر الأوامر. كل ما تكتبه بعد اسم الصنف في أمر java ينتهي في ذلك المصفوف:
على جهازك الخاص ستمرّر إليه الوسائط هكذا:
java Main hello world
First argument: hello
Total arguments: 2
لا يستطيع المحرر بالأعلى أن يتلقى وسائط من الطرفية، لذا يشغّل فرع "لا وسائط" - لكن الشيفرة نفسها تتعامل مع الحالتين. هكذا تقرأ برامج Java المُدخلات المُمرَّرة وقت التشغيل، قبل وقت طويل من وصولك إلى الملفات أو مُدخلات المستخدم.
قراءة رسائل خطأ المُصرِّف
حين يرفض javac شيفرتك، يخبرك بالملف والسطر وما الذي حدث خطأً. وتعلّم قراءة هذه الرسائل هو نصف الطريق للخروج من المأزق. وإليك مثالًا كلاسيكيًا - فاصلة منقوطة ناقصة:
public class Main {
public static void main(String[] args) {
System.out.println("Oops") // no semicolon
}
}
Main.java:3: error: ';' expected
System.out.println("Oops")
^
1 error
تشير علامة الإقحام (^) إلى الموضع الذي توقّع فيه المُصرِّف شيئًا. وMain.java:3 هو الملف ورقم السطر. قاوم الرغبة في التخمين - اقرأ السطر، وأصلح الشيء الوحيد الذي يسمّيه، وأعد التصريف. أخطاء التصريف تعني أن شيئًا لم يُشغَّل بعد؛ أما أخطاء وقت التشغيل (التي تبدو مختلفة) فتعني أن برنامجك بدأ ثم فشل.
برنامج للتحقق من سلامة الإعداد
شغّل هذا في المحرر، أو احفظه باسم Main.java ونفّذ javac Main.java ثم java Main على جهازك الخاص. إن رأيت الأسطر الثلاثة جميعًا، فإن سلسلة أدواتك تعمل من البداية إلى النهاية:
تظهر هنا ثلاثة أشياء ستلتقي بها على وجهها الصحيح قريبًا: متغير int، وضمّ السلاسل النصية بـ+، ومصفوف مع .length الخاص به. ويكفي الآن أن يُصرَّف البرنامج ويطبع.
التالي: صياغة Java
شغّلت بضعة برامج، لكننا تجاوزنا علامات الترقيم بإيماءات سريعة - الأقواس المعقوفة، والفواصل المنقوطة، وpublic static void main، ولماذا يبدو كل سطر على ما هو عليه. تفكّك الصفحة التالية صياغة Java قطعةً قطعةً كي يكفّ هيكلها عن الإحساس بأنه نمط متكرر ويبدأ في اكتساب المعنى.
الأسئلة الشائعة
كيف أشغّل برنامج Java؟
احفظ شيفرتك في ملف يحمل اسم الصنف العام نفسه (مثل Main.java)، وافتح طرفية في ذلك المجلد، ونفّذ أمرين: javac Main.java لتصريفه إلى بايت كود، ثم java Main لتشغيله. مع JDK 11 أو أحدث يمكنك تخطي الخطوة الأولى لملف واحد وتشغيل java Main.java مباشرةً.
ما الفرق بين javac وjava؟
javac هو المُصرِّف: يقرأ مصدرك .java وينتج ملف .class مليئًا بالبايت كود. أما java فهو المُشغِّل: يبدأ آلة JVM ويشغّل البايت كود الموجود في ملف .class. تُصرِّف مرة واحدة باستخدام javac، ثم تشغّل بقدر ما تشاء باستخدام java.
لماذا تظهر لي رسالة "could not find or load main class"؟
في الغالب الأعم لأنك مرّرت الاسم الخاطئ إلى java. استخدم اسم الصنف، لا اسم الملف: الصحيح هو java Main، وليس java Main.class ولا java Main.java. وتأكد أيضًا من أنك في المجلد الذي يحتوي على Main.class وأن اسم الصنف يطابق اسم الملف تمامًا، بما في ذلك حالة الأحرف.