السابقالفهرسالتالي

الفصل 2

المتغيرات وأنواع البيانات

 

2.1 المزيد من الطباعة

يمكنك أن تضع العدد الذي ترغب فيه من التعليمات في main. مثلاً، لطباعة أكثر من سطر واحد من النص:

class Hello {

   // Generates some simple output.

   public static void main(String[] args) {
      System.out.println("Hello, world."); 	// print one line
      System.out.println("How are you?"); 	// print another
   }
}
كما هو واضح من هذا المثال، يمكنك وضع التعليقات في نهاية السطر، كما يجوز أن تترك سطراً كاملاً لها. العبارات التي تظهر بين علامات الاقتباس تدعى سلاسل محرفية (strings)، لأنها مكونة من تتابع (تسلسل) للمحارف. يمكن أن تحتوي السلاسل المحرفية على أي توليفة من الحروف، والأرقام، وعلامات الترقيم ومحارف خاصة أخرى.

println هي اختصار ل"print line"، لأنها تضيف بعد كل سطر تطبعه محرفاً خاصاً، يدعى محرف السطر الجديد (new line)، يحرك مؤشر الطباعة إلى السطر التالي من شاشة العرض. في المرة التالية التي سيتم استدعاء println فيها، سيظهر النص على السطر التالي. لإظهار الخرج من عدة تعليمات طباعة على سطر واحد، استخدم print:

class Hello {

   // Generates some simple output.

   public static void main(String[] args) {
      System.out.print("Goodbye, ");
      System.out.println("cruel world!");
   }
} 
في هذه الحالة سيظهر الخرج على سطر واحد كما في Goodbye, cruel world!. لاحظ وجود الفراغ بين الكلمة "Goodbye," وعلامة الاقتباس الثانية. هذا الفراغ سيظهر في الخرج، فهو يؤثر إذن في سلوك البرنامج. الفراغات التي تظهر خارج علامات الاقتباس لا تؤثر في عمل البرنامج عادة. مثلاً، كان بإمكاني كتابته كما يلي:
class Hello {
public static void main(String[] args) {
System.out.print("Goodbye, ");
System.out.println("cruel world!");
}
}
هذا البرنامج سيترجم وينفذ تماماً كالأصلي. كتابة البرنامج على عدة أسطر لا تؤثر على عمل البرنامج أيضاً، لذا فمن الممكن أن أكتبه كما يلي:
class Hello { public static void main(String[] args) {
System.out.print("Goodbye, "); System.out.println("cruel world!");}}
هذا البرنامج سيعمل أيضاً، إلا أنك قد لاحظت على الأغلب أن البرنامج أصبح أصعب للقراءة في كل مرة. الأسطر الجديدة والفراغات مفيدة لترتيب البرنامج بصرياً، مما يجعل البرنامج أسهل للقراءة والأخطاء النحوية (syntax errors) أسهل للتصحيح.

2.2 المتغيرات

أحد أقوى المزايا لأي لغة برمجة هي القدرة على معالجة المتغيرات (variables). المتغير هو منطقة ذات اسم تخزّن قيمة (value). القيم هي الأشياء التي يمكن طباعتها، وتخزينها و(كما سنرى لاحقاً) تطبيق العمليات عليها. السلاسل المحرفية التي كنا نطبعها
("Hello, World."، "Goodbye, "، الخ) هي قيم. لتخزين قيمة، عليك إنشاء متغير. بما أن القيم التي نريد تخزينها هي سلاسل محرفية، سنصرح عن المتغير على أنه سلسلة محرفية (String):

String fred;
هذا النوع من التعليمات يدعى تصريح (declaration)، لأنها تصرح أن نوع المتغير المدعو fred هو String. لكل متغير نوع يحدد نوع القيم التي يمكنه تخزينها. مثلاً، النوع int يمكنه تخزين الأعداد الصحيحة، والنوع String يمكنه تخزين السلاسل المحرفية. بعض الأنواع تبدأ بحرف كبير وبعضها الآخر يبدأ بحرف صغير. سنعرف معنى هذا التمييز لاحقاً، لكن الآن عليك الانتباه له حتى تفهمه بشكل صحيح. لا يوجد نوع مثل Int أو string، وسيعترض المجمع لو حاولت اختراع مثل هذه الأنواع.

لإنشاء متغير من النوع الصحيح، التعليمة هي

int bob;
حيث bob هو الاسم الكيفي الذي تختاره للمتغير. بصورة عامة، سترغب باختيار أسماء للمتغيرات بحيث تشير إلى دور المتغير في البرنامج. مثلاً، عندما ترى التصريحات التالية عن المتغيرات:
String firstName;
String lastName;
int hour, minute; 
ستتمكن على الأغلب من تخمين ماهية القيم التي ستخزن فيها. هذا المثال يوضح أيضاً كيفية التصريح عن عدة متغيرات من نفس النوع في تعليمة واحدة: كلاً من hour و minute هو عدد صحيح (من النوع int).

2.3 الإسناد

بعد أن أنشأنا بعض المتغيرات، سنقوم بتخزين بعض القيم فيها. يمكننا عمل ذلك باستخدام تعليمة الإسناد (assignment statement).

fred = "Hello."; 	// give bob the value "Hello." 
hour = 11;		// assign the value 11 to hour
minute = 59;		// set minute to 59
هذا المثال يبين ثلاث تعليمات إسناد، والتعليقات تظهر ثلاثة أساليب يستخدمها الناس أحياناً عندما يقرؤون تعليمات الإسناد. المفردات قد تكون مربكة هنا، لكن الفكرة واضحة :

من الطرق الشائعة للتعبير عن المتغيرات على الورق رسم صندوق وكتابة اسم المتغير خارجه وقيمة المتغير بالداخل. هذا المخطط يبين أثر تعليمات الإسناد الثلاث:

كقاعدة عامة، يجب أن يكون نوع المتغير من نفس نوع القيمة التي تسندها إليه. مثلاً، لا يمكنك تخزين سلسلة محرفية في المتغير minute أو عدداً صحيحاً في fred. من ناحية أخرى، هذه القاعدة قد تكون مصدراً للإرباك أحياناً، بسبب وجود العديد من الطرق التي تسمح لك بتحويل القيم من نوع لآخر، وأحياناً تحول Java الأشياء تلقائياً. لكن الآن عليك فقط أن تتذكر القاعدة العامة بأن المتغيرات والقيم يجب أن تكون من نفس النوع، وسنتحدث عن الحالات الخاصة لاحقاً.

من مصادر الإرباك الأخرى هو أن بعض السلاسل المحرفية تبدو مثل الأرقام، لكنها ليست كذلك. مثلاً، يمكن أن يخزن fred السلسلة المحرفية "123"، المكونة من المحارف 1 و 2 و 3، لكنها ليست مثل العدد 123.

fred = "123"; 	// legal
fred = 123; 	// not legal

2.4 طباعة المتغيرات

يمكنك طباعة قيمة متغير باستخدام println أو print:

class Hello {
  public static void main(String[] args) {
    String firstLine;
    firstLine = "Hello, again!";
    System.out.println(firstLine);
  }
}
هذا البرنامج ينشئ متغيراً باسم firstLine، ويسند له القيمة "Hello, Again!" ثم يطبع تلك القيمة.

عندما نتحدث عن "طباعة متغير"، فنحن نعني طباعة قيمة المتغير. أما لطباعة اسم المتغير، فعليك أن تضعه بين علامتي اقتباس. مثلاً:

System.out.println("firstLine");
مثلا، يمكنك كتابة
String firstLine;
firstLine = "Hello, again!";
System.out.print("The value of firstLine is ");
System.out.println(firstLine);
سيكون خرج هذا البرنامج هو
The value of firstLine is Hello, again!

بنية تعليمة طباعة متغير هي نفسها بغض النظر عن نوع المتغير.

int hour, minute;
hour = 11;
minute = 59;
System.out.print("The current time is ");
System.out.print(hour);
System.out.print(":");
System.out.print(minute);
System.out.println(".");
خرج هذا البرنامج هو The current time is 11:59.

تنـويه: لوضع عدة قيم على نفس السطر، من الشائع استخدام عدة تعليمات print. لكن عليك أن تتذكر وضع println في النهاية. في العديد من بيئات البرمجة، يتم تخزين خرج تعليمات print بدون عرضه على الشاشة حتى استدعاء println، وعندها يظهر السطر كله دفعة واحدة. إذا أغفلت println، فقد ينتهي برنامجك بدون طباعة الخرج المخزن!

2.5 الكلمات المفتاحية

قبل عدة أقسام، أخبرتك أنك تستطيع اختيار أي اسم لمتغيراتك، لكنّ ذلك ليس صحيحاً تماماَ. هناك كلمات معينة محجوزة في Java لأن المترجم يستخدمها لإعراب (parse) بنية برنامجك، وإذا استخدمتها كأسماء للمتغيرات، سيرتبك المترجم. هذه الكلمات، تدعى الكلمات المفتاحية (keywords)، وهي تتضمن الكلمات public، class، void، int، وغيرها الكثير.

القائمة الكاملة للكلمات المفتاحية موجودة على
http://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html، هذا الموقع، المقدم من شركة أوراكل، يحتوي على توثيق Java الذي أعتمد إليه في هذا الكتاب.

بدلاً من حفظ القائمة، سأقترح أن تستفيد من ميزة تقدمها معظم بيئات البرمجة: تلوين الشفرة. بينما تكتب البرنامج، الأجزاء المختلفة منه ستظهر في ألوان مختلفة. مثلاً، الكلمات المفتاحية قد تكون باللون الأزرق، السلاسل المحرفية بالأحمر، وبقية الشفرة بالأسود. إذا كتبت اسماً لمتغير وتغير لونه إلى الأزرق، فانتبه! قد تنتج أفعال غريبة عن المترجم.

2.6 العوامل

العوامل (operators) هي رموز خاصة تستعمل للتعبير عن الحسابات البسيطة مثل الجمع والضرب. معظم العوامل في Java تفعل ما تتوقعه منها تماماً لأنها رموز رياضية شائعة. مثلاً، عامل جمع عددين هو +. عامل الطرح هو - ، وللضرب *، وللقسمة /.

1+1       hour-1        hour*60 + minute        minute/60

يمكن للعبارات الحسابية أن تحتوي على أسماء متغيرات وأرقام. يتم استبدال المتغيرات بقيمها قبل إجراء الحساب.

يتم تنفيذ الجمع، الطرح والضرب تماماً كما هو متوقع، لكنك قد تفاجأ بعملية القسمة. مثلاً، البرنامج التالي:

int hour, minute;
hour = 11;
minute = 59;
System.out.print("Number of minutes since midnight: ");
System.out.println(hour*60 + minute);
System.out.print("Fraction of the hour that has passed: ");
System.out.println(minute/60);
سيولد النتيجة التالية:
Number of minutes since midnight: 719
Fraction of the hour that has passed: 0
السطر الأول يوافق ما توقعناه، لكن السطر الثاني غريب. قيمة المتغير minute هي 59، و59 مقسومة على 60 يعطي 0.98333، وليس 0. إن سبب هذا التناقض هو أن Java نفذت عملية القسمة الصحيحة (integer division).

عندما يكون كلا المعاملين (operands) صحيحين (المعامل هو الشيء الذي تعمل عليه العوامل)، يجب أن تكون النتيجة عدداً صحيحاً أيضاً، وبحسب تعريفها فإن القسمة الصحيحة دائماً تقرب النتائج إلى الأدنى، حتى في الحالات التي يكون الناتج فيها قريباً جداً من العدد الصحيح التالي. من الحلول البديلة في هذه الحالة هو حساب النسبة المئوية بدلاً من العدد الكسري:

System.out.println("Percentage of the hour that has passed: ");
System.out.println(minute*100/60);
النتيجة هي:
Percentage of the hour that has passed: 98
مرة أخرى، يتم تقريب النتيجة إلى العدد الأدنى، لكن على الأقل فالإجابة صحيحة تقريباً هذه المرة. للحصول على إجابة أكثر دقة، يمكننا استعمال نوع آخر من المتغيرات، يدعى متغير النقطة العائمة (floating-point)، الذي يستطيع تخزين القيم الكسرية. سنشرح ذلك في الفصل التالي.

2.7 أولوية العمليات الحسابية

عندما يظهر أكثر من عامل في تعبير حسابي فإن ترتيب الحسابات يعتمد على قواعد الأولوية (precedence). الشرح الكامل للأولوية يمكن أن يصبح معقداً، لكن أن نقول كبداية أن:

2.8 عوامل السلاسل المحرفية

بصورة عامة، لا يمكنك إجراء عمليات حسابية على السلاسل المحرفية، حتى لو بدت السلسلة كرقم. التعليمات التالية غير مشروعة (إذا علمنا أن bob من النوع String)

bob - 1 		"Hello"/123 			bob * "Hello"
بالمناسبة، هل يمكنك معرفة فيما إذا كان bob من نوع int أو String بالنظر إلى هذه العبارات؟ لا، الطريقة الوحيدة لمعرفة نوع متغير تكون بالنظر إلى المكان الذي تم التصريح عنه فيه. مما يثير الاهتمام، أن العامل + يعمل على السلاسل المحرفية، لكنه قد لا يقوم بما هو متوقع. بالنسبة للسلاسل المحرفية، يمثل العامل + عملية ربط السلاسل (concatenation)، أي دمج المعاملين بربطهما معاً، نهاية الأول إلى بداية الثاني. لذا فإن "Hello, " + "world." ستعطي السلسلة "Hello, world." وbob + "ism" تضيف اللاحقة ism إلى آخر الكلمة المخزنة في bob، وهو ما قد يكون مفيداً عند تسمية الأنواع الجديدة من التعصبات (bigotry).

2.9 التركيب

حتى الآن تعرفنا على عناصر لغة البرمجة ─ المتغيرات، العبارات الحسابية، والتعليمات ─ بشكل معزول، بدون التحدث عن كيفية تجميعهم.

أحد أفضل مزايا لغات البرمجة هو قدرتها على أخذ قوالب بناء صغيرة وتركيبها (compose). مثلاً، نحن نعرف كيفية ضرب الأعداد ونعرف كيف نخرج القيم؛ هذا يؤدي إلى أننا نستطيع جمع الاثنين في تعليمة واحدة:

System.out.println(17 * 3);
أي تعبير، يحوي أرقاماً، سلاسل محرفية، ومتغيرات، يمكن استعماله ضمن تعليمة الطباعة. وقد شاهدنا مثالاً على ذلك من قبل:
System.out.println(hour*60 + minute);
يمكنك أيضاً وضع عبارات كيفية على يمين تعليمة الإسناد:
int percentage;
percentage = (minute * 100) / 60;
هذه القدرة قد لا تكون مدهشة الآن، لكننا سنرى أمثلة أخرى يمكننا التركيب فيها من التعبير عن الحسابات المعقدة بشكل مختصر ومحكم.

تنويه: يجب أن يكون الطرف الأيسر من تعليمة الإسناد اسم متغير، وليس عبارة رياضية. ذلك لأن الطرف الأيسر يشير إلى المنطقة التخزينية التي ستخزن فيها النتائج. العبارات الرياضية لا تمثل مناطق تخزينية، بل تمثل قيماً فقط. لذا فالتعليمة التالية غير صحيحة: minute+1 = hour;.

2.10 المصطلحات

المتغير: منطقة لتخزين القيم ولها اسم. كل متغير له نوع، يتم التصريح عنه عند إنشاء المتغير.

القيمة: سلسلة محرفية، أو رقم، (أو أي شيء آخر مما سنتعرف عليه لاحقاً) يمكن تخزينه في متغير. كل قيمة تنتمي لنوع معين.

النوع: مجموعة من القيم. نوع المتغير يحدد القيم التي يمكن تخزينها فيه. الأنواع التي شاهدناها حتى الآن هي الأعداد الصحيحة (int في Java) والمحارف (char في Java).

الكلمة المفتاحية: كلمة محجوزة يستخدمها المترجم لإعراب البرامج. لا يمكنك استخدام الكلمات المفتاحية مثل public، class، وvoid كأسماء للمتغيرات.

التصريح: تعليمة تقوم بإنشاء متغير جديد وتحدد نوعه.

الإسناد: تعليمة تعطي قيمة إلى متغير.

العبارة الرياضية: مجموعة من المتغيرات، والعوامل والقيم التي تمثل قيمة ناتجة وحيدة. للعبارات أنواع أيضاً، تحدد بعواملها ومعاملاتها.

العامل: رمز خاص يمثل عملية حسابية، مثل الجمع أو الضرب أو ربط السلاسل.

المعامل: أحد القيم التي يعمل عليها العامل.

الأولوية: الترتيب الذي يتم تنفيذ العمليات الحسابية وفقه.

ربط السلاسل: جمع المعاملين طرف الأول إلى طرف الثاني.

التركيب: القدرة على تجميع التعابير البسيطة والتعليمات في تعليمات وتعابير مركبة في سبيل تمثيل الحسابات المعقدة بشكل مختصر.

variable: A named storage location for values. All variables have a type, which is declared when the variable is created.

value: A number or string (or other thing to be named later) that can be stored in a variable. Every value belongs to a type.

type: A set of values. The type of a variable determines which values can be stored there. The types we have seen are integers (int in Java) and strings (String in Java).

keyword: A reserved word used by the compiler to parse programs. You cannot use keywords, like public, class and void as variable names.

declaration: A statement that creates a new variable and determines its type.

assignment: A statement that assigns a value to a variable.

expression: A combination of variables, operators and values that represents a single value. Expressions also have types, as determined by their operators and operands.

operator: A symbol that represents a computation like addition, multiplication or string concatenation.

operand: One of the values on which an operator operates.

precedence: The order in which operations are evaluated.

concatenate: To join two operands end-to-end.

composition: The ability to combine simple expressions and statements into compound statements and expressions to represent complex computations concisely.

2.11 تمرينات

تمرين 2.1

قد تستمتع في هذا التمرين: ابحث عن شريك والعب معه "Stump the Chump" – "اخدع المغفل".

ابدأ مع برنامج تتم ترجمته وتشغيله بشكل صحيح. يبتعد أحد اللاعبين بينما يقوم الآخر بعمل خطأ في البرنامج. بعدها يحاول اللاعب الآخر العثور على ذلك الخطأ وإصلاحه. تحصل على نقطتين إذا عثرت على الخطأ بدون تجميع البرنامج، ونقطة واحدة أغذا عثرت عليه بالاستعانة بالمترجم، ويحصل خصمك على نقطة إذا لم تعثر عليه.

ملاحظة: من فضلك لا تحذف "l" من كلمة "public". فذلك ليس ممتعاً كما تعتقد.

تمرين 2.2

  1. أنشئ برنامجاً جديداً باسم Date.java. انسخ أو اكتب برنامجاً يشبه "Hello, world" وتأكد من تجميعه وتشغيله.
  2. بالاستعانة بالمثال في القسم 2.4، اكتب برنامجاً ينشئ متغيرات جديدة تدعى day، date، month، وyear. سيحتوي day على اليوم من الأسبوع وdate على اليوم من الشهر. ما هو نوع كل متغير؟ أسند قيماً لهذه المتغيرات بحيث تمثل تاريخ اليوم.
  3. اطبع قيمة كل متغير على سطر لوحده. هذه خطوة انتقالية للتأكد من أن كل شيء على ما يرام حتى الآن.
  4. عدل البرنامج بحيث يطبع التاريخ في التنسيق الأمريكي القياسي: Saturday, August 13, 2011.
  5. عدل البرنامج ثانية حتى يصبح الخرج كما يلي:
    American format:
    Saturday, August 13, 2011
    European format:
    Saturday 13 August, 2011
    

إن الغرض من هذا التمرين هو استخدام ربط السلاسل لعرض القيم ذات الأنواع المختلفة (int وString)، والتدرب على تطوير البرامج تدريجياً بإضافة عدد قليل من التعليمات في كل مرة.

تمرين 2.3

  1. أنشئ برنامجاً جديداً باسم Time.java. من الآن فصاعداً لن أذكرك أن تبدأ مع برنامج صغير صحيح، لكن عليك أن تفعل ذلك.
  2. بالاستعانة بالمثال من القسم 2.6، أنشئ متغيرات باسم hour، minute، وsecond، وأسند لها قيماً تمثل الوقت الحالي تقريباً. استعمل نظام 24 ساعة؛ بحيث تكون قيمة hour التي تمثل 2 بعد الظهر هي 14.
  3. اصنع برنامجاً يحسب ويطبع عدد الثواني المنقضية منذ منتصف الليل.
  4. اصنع برنامجاً يحسب ويطبع عدد الثواني المتبقية للنهار.
  5. اصنع برنامجاً يحسب النسبة المئوية التي انقضت من النهار.
  6. غير قيم hour، وminute وsecond لتعاكس قيم الوقت الحالي (هذه هي المدة التي أعتقد أنها قد انقضت الآن)، وتحقق من أن البرنامج يعمل مع مختلف القيم.

الغرض من هذا التمرين هو استخدام بعض العمليات الحسابية، والبدء بالتفكير بعناصر مركبة مثل الوقت الذي يمثل بعدة قيم. أيضاً، قد تواجهك مشاكل عند حساب النسبة المئوية باستخدام الأعداد الصحيحة، وهو الدافع لدراسة الأعداد العشرية في الفصل التالي.

مساعدة: قد تحتاج لاستعمال متغيرات إضافية لتخزين بعض القيم مؤقتاً خلال عملية الحساب. إن مثل هذه المتغيرات التي نستخدمها في العمليات الحسابية لكن لا تتم طباعتها أبداً، تدعى أحياناً بالمتغيرات الوسيطة أو المؤقتة.

السابقالفهرسالتالي