اذهب إلى المحتوى

المتغيرات والأنواع البسيطة في لغة جافا


رضوى العربي

تُعدّ الأسماء واحدة من أساسيات البرمجة حيث تُستخدَم بالبرامج للإشارة إلى كثير من الأشياء المختلفة. لابُدّ من فهم قواعد تَسْمية الأشياء وطريقة اِستخدَام الأسماء لكي تَتَمكَّن من اِستخدَام الأشياء أي تحتاج في العموم إلى فهم كُلًا من صيغة (syntax) الأسماء ودلالتها (semantics).

وفقًا لقواعد الصيغة (syntax rules) بالجافا، المُعرّفات (identifiers) واحدة من أبسط الأسماء، وتُستخدَم لتسمية كُلًا من الأصناف (classes) والمُتْغيِّرات (variables) والبرامج الفرعية (subroutines). يَتَكوَّن أي مُعرّف من متتالية تتألف من محرف (character) واحد أو أكثر بشَّرْط أن يَكُون أول محرف حرفًا أبجديًا (letter) أو شرطة سفلية (underscore) _، وأن تَكوُن المتتالية بالكامل مُكوَّنة من حروف أبجدية وأرقام (digits) وشرط سفلية فقط. اُنظر الأمثلة التالية لأسماء مُعرّفات (identifiers) صالحة:

N   n   rate  x15   quite_a_long_name   HelloWorld

لا يُسمَح للمسافات الفارغة (spaces) بأن تَكُون جزءًا من اسم أي مُعرّف، فمثلًا، في حين تستطيع اِستخدَام HelloWorld كاسم مُعرّف، لا يُمكِنك أن تَستخدِم "Hello World". تختلف كذلك الحروف الكبيرة عن الحروف الصغيرة فيما يَتَعلَّق بالتسمية أي أن الأسماء HelloWorld و helloworld و HELLOWORLD و hElloWorLD هي أسماء مُعرّفات مختلفة. بالإضافة إلى ذلك، لا يُمكِنك اِستخدَام الكلمات المحجوزة (reserved) المُخصَّصة لأغراض خاصة بالجافا كأسماء مُعرِّفات مثل الكلمات class و public و static و if و else و while وعشرات من الكلمات الآخرى. لاحِظ أن الكلمات المحجوزة ليست مُعرّفات فهي لا تُستخدَم كأسماء تُشير إلى أشياء.

تَستخدِم الجافا محارف اليونيكود (Unicode character set) والتي تَتَضمَّن آلافًا من المحارف والحروف الأبجدية (alphabets) من مختلف اللغات. تُعدّ كثير من تلك المحارف بمثابة حروف أبجدية أو أرقام. سنَقْتصِر عمومًا على اِستخدَام المحارف المُتوفِّرة بأي لوحة مفاتيح إنجليزية عادية فقط.

هنالك بعض الاصطلاحات والقواعد الإرشادية التي ينبغي اتباعها في العموم عند تَسْمية (naming) الأشياء. أولًا، تبدأ أسماء الأصناف (classes) بحروف كبيرة (upper case) بعكس أسماء كُلًا من المُتْغيِّرات (variables) والبرامج الفرعية (subroutines) والتي تبدأ عادةً بحروف صغيرة (lower case). يُساعِد الالتزام بذلك التَقْليد (convention) على تَجنُّب أي خلط مُحتمَل. ثانيًا، لا يَستخدِم غالبية مُبرمجي الجافا الشُرط السُفليّة (underscores) بالأسماء مع أن البعض يلجأ إلى اِستخدَامها ببداية أسماء أنواع مُحدَّدة من المُتْغيِّرات (variables). ثالثًا، إذا كان الاسم مُكوَّن من عدة كلمات مثل HelloWorld أو interestRate، فيُعتاد تَكْبير الحرف الأول (capitalize) من كل كلمة باستثناء الأولى فيما يُعرَف باسم نَمْط سنام الجمل (camelCase) حيث تُشبه الحروف الأبجدية الكبيرة (upper case) بمنتصف الاسم سنام الجمل.

بالإضافة إلى الأسماء البسيطة (simple names)، قد تَكُون الأسماء أيضًا مُركَّبة من عدة أسماء بسيطة يَفصِل بين كُلًا منها نقطة (period) مثل الاسم System.out.println، وتُعرَف باسم "الأسماء المُؤهلة (qualified names)". لأن الجافا تَسمَح بتَضْمِين الأشياء ضِمْن بعضها البعض، فإن الاسم المُركَّب يَعمَل كمسار إلى شيء عبر واحد أو أكثر من مستويات الاحتواء (containment level)، فمثلًا يُشير الاسم System.out.println إلى شيء اسمه System يحتوي على شيء آخر اسمه out والذي بدوره يحتوي على شيء اسمه printn.

المتغيرات (variables)

تُستخدَم البرامج في العموم لمُعالجة البيانات المُخزَّنة بذاكرة الحاسوب. إذا كنا نُبرمج باِستخدَام لغة الآلة (machine language)، فإننا نَكُون مُضطرّين لاِستخدَام العنوان العددي (numerical memory address) لمَوضِع الذاكرة لكي نَتَمكَّن من الإشارة إلى البيانات المُخزَّنة به أما باللغات عالية المستوى (high-level language) مثل الجافا، فإننا في العموم نَستخدِم أسماءً وليس أعدادًا للإشارة إلى بيانات الذاكرة أي لا يحتاج المبرمج إلى ما هو أكثر من تَذكُّر تلك الأسماء، والتي يُطلَق عليها اسم "المُتْغيِّرات (variables)"، وفي المقابل، يَتعقَب الحاسوب مواضع الذاكرة الفعليّة لتلك البيانات.

لا يُعدّ المُتْغيِّر (variable) اسمًا للبيانات نفسها وإنما لمَوضِع الذاكرة الحامل لتلك البيانات أي أنه يَعمَل كصندوق أو كحاوي يُمكِنك أن تُخزِّن به بعض البيانات التي قد تحتاج إليها لاحقًا. يُشير أي مُتْغيِّر إذًا إلى صندوق بصورة مباشرة وإلى البيانات الموجودة بذلك الصندوق بصورة غير مباشرة. لمّا كانت البيانات المُخزَّنة بالصندوق قابلة للتَعْديل، فقد يشير مُتْغيِّر معين إلى بيانات مختلفة بلحظات مختلفة من تّنْفيذ البرنامج، ولكنه دائمًا ما سيُشير إلى نفس الصندوق. عندما نَستخدِم مُتْغيِّرًا ضِمْن برنامج، فإنه -وبحسب الطريقة التي اُستخدِم بها ذلك المُتْغيِّر- إما يُشير إلى صندوق وإما إلى البيانات المُخزَّنة بذلك الصندوق، وهو ما قد يَكُون مُربِكًا لبعض المبرمجين المبتدئين. سنَفْحَص أمثلة لكلا الحالتين بالأسفل.

تُستخدَم تَعْليمَات الإسناد (assignment statement) بالجافا لتَخْزين بيانات معينة بمُتْغيِّر أي بصندوق، وتُكْتَب على النحو التالي:

<variable> = <expression>;

يُمثِل التعبير -بالأعلى- أي شيء طالما كان يُشير إلى قيمة بيانات أو يَحسِبها. عندما يُنفِّذ الحاسوب تَعْليمَة إسناد معينة، فإنه يُحصِّل (evaluates) قيمة ذلك التعبير ثم يُخزِّنها بالمُتْغيِّر . اُنظر تَعْليمَة الإسناد (assignment statement) التالية على سبيل المثال:

rate = 0.07;

بالتَعْليمَة السابقة، يُمثِل rate المُتْغيِّر أما القيمة 0.07 فتُمثِل التعبير . تُخزِّن تَعْليمَة الإسناد السابقة القيمة 0.07 بالمُتْغيِّر rate بحيث تحلّ تلك القيمة محلّ قيمته السابقة. سنَفْحَص الآن مثالًا آخر لتَعْليمَة إِسناد أكثر تعقيدًا بقليل، والتي سنحتاج إليها لاحقا ضِمْن البرنامج:

interest = rate * principal;

تُسنِد تَعْليمَة الإسناد (assignment statement) بالأعلى قيمة التعبير rate * principal إلى المُتْغيِّر interest. يُشير المحرف * الموجود بالتعبير إلى "عامِل حاصل الضرب (multiplication operator)" المسئول عن حساب حاصل ضرب rate في principal. لمّا كانت الأسماء rate و principal ضِمْن التعبير هي نفسها مُتْغيِّرات، يُحسَب حاصل ضرب القيم المُخزَّنة بتلك المُتْغيِّرات أي يُحسَب حاصل ضرب قيمة rate في قيمة principal ثم تُخزَّن الإجابة بالصندوق الذي يُشير إليه interest. نستطيع أن نقول إذًا أنه وفي العموم عندما نَستخدِم مُتْغيِّرًا ضِمْن تعبير (expression)، فإن القيمة المُخزَّنة بذلك المُتْغيِّر هي كل ما يُهِمّ، ويبدو المُتْغيِّر في تلك الحالة كما لو كان يُشير إلى بيانات الصندوق وليس الصندوق ذاته. في المقابل، عندما نَستخدِم مُتْغيِّرًا على الجانب الأيسر من تَعْليمَة إسناد، فإنه في تلك الحالة يُشير إلى الصندوق ذاته المُمثِل لذلك المُتْغيِّر.

تَعْليمَات الإِسناد ليست تَعْليمَات خبرية، وإنما هي بمثابة أوامر يُنفِّذها الحاسوب بأوقات محددة. لنَفْترِض مثلً أن برنامجًا معينًا يُنفِّذ التَعْليمَة rate = 0.07;‎ ثم يُنفِّذ التَعْليمَة interest = rate * principal;‎ بوقت لاحق ضِمْن البرنامج، هل يُمكِننا ببساطة أن نَدعِي أننا قد ضربنا principal بالقيمة 0.07؟ في الواقع لا! لأن قيمة rate قد تَتَغيَّر في أي لحظة بواسطة تَعْليمَة إِسناد آخرى. يختلف معنى تَعْليمَة الإِسناد تمامًا عن معنى أي معادلة رياضية على الرغم من أن كليهما يَستخدِم الرمز =.

الأنواع (types)

يُمكِن لأي مُتْغيِّر (variable) بالجافا أن يَحمِل نوعًا (type) واحدًا فقط من البيانات وليس أي نوع آخر. إذا حاولت أن تُسنِد (assigning) قيمة من نوع مختلف عن نوع مُتْغيِّر معين إلى ذلك المُتْغيِّر، فسيُعدّ ذلك انتهاكًا لتلك القاعدة، وسيُبلِّغ عنه المُصرِّف (compiler) على أساس كَوْنه خطأ في بناء الجملة (syntax error). نقول إذًا أن الجافا هي لغة صارمة في تَحْديد النوع (strongly typed language).

تُوفِر الجافا 8 أنواع أساسية (primitive types) مَبنية مُسْبَقًا هي كالتالي: byte و short و int و long و float و double و char و boolean. تَحمِل الأنواع الأربعة الأولى أعدادًا صحيحة (integers) مثل 17 و ‎-38477 و 0، ولكنها تختلف عن بعضها فيما يَتعَلَّق بنطاق الأعداد الصحيحة التي يُمكِن لكل نوع منها حَمْله. في المقابل، يَحمِل النوعان float و double أعدادًا حقيقية (real numbers) مثل 3.6 و ‎-145.99، ويختلفان عن بعضهما بكُلًا من نطاق الأعداد المسموح به وبدقة العَدَد. تستطيع المُتْغيِّرات من النوع char أن تَحمِل إحدى محارف اليونيكود (Unicode character set) أما المُتْغيِّرات من النوع boolean فتَحمِل إما القيمة المنطقية true أو القيمة false.

تُمثَل جميع قيم البيانات بذاكرة الحاسوب بهيئة عدد من النظام الثُنائي (binary number) عبارة عن سِلسِلة نصية (string) مُكوَّنة من الرقمين صفر وواحد. يُطلَق اسم "بت (bit)" على كُلًا منها بينما يُطلَق اسم "بايت (byte)" على أي سِلسِلة نصية مُكوَّنة من ٨ بتات، وتُقاس الذاكرة عادةً بتلك الوحدة. يُشير النوع byte إلى بايت واحد فقط بالذاكرة أي تَحمِل المُتْغيِّرات (variable) من النوع byte سِلسِلة نصية من ٨ بتات يُمكِنها أن تُمثِل ٢٥٦ عددًا صحيحًا (٢ مرفوعة للأس ٨) أي قد تُمثِل أي عدد صحيح بين -١٢٨ و ١٢٧. أما بالنسبة للأنواع الصحيحة (integer) الآخرى:

  • short يُمثِل ٢ بايت (١٦ بت)، وتَحمِل المُتْغيِّرات من النوع short قيم ضِمْن نطاق يتراوح من ‎-32768 إلى 32767.
  • int يُمثِل ٤ بايت (٣٢ بت)، وتَحمِل المُتْغيِّرات من النوع int قيم تتراوح من ‎-2147483648 إلى 2147483647.
  • long يُمثِل ٨ بايت (٦٤ بت)، وتَحمِل المُتْغيِّرات من النوع long قيم بنطاق يتراوح من ‎-9223372036854775808 إلى 9223372036854775807.

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

أما النوع float فيَستخدِم طريقة ترميز (encoding) قياسية لتمثيل الأعداد الحقيقية (real) بمساحة ٤ بايت من الذاكرة، ويُمكِنه أن يَحمِل قيمة قصوى تَصِل إلى ١٠ مرفوعة للأس ٣٨. علاوة على ذلك، يُمكِن للقيم من النوع float أن تَشتمِل على ٧ أرقام معنوية (significant digits) بحد أقصى. لابُدّ إذًا من تَقْرِيب كُلًا من العددين 32.3989231134 و 32.3989234399 إلى العَدَد 32.398923 حتى نَتَمكَّن من تَخْزِينه بمُتْغيِّر من النوع float. في المقابل، يُمثِل النوع double الأعداد الحقيقية بمساحة ٨ بايت، لذا يُمكِنه أن يَحمِل قيمة قصوى تَصِل إلى ١٠ مرفوعة للأس ٣٠٨، وقد يَشتمِل على ١٥ رقم معنوي (significant digit). في العموم عادةً ما يُستخدَم النوع double لتمثيل قيم الأعداد الحقيقية.

أما المُتْغيِّرات من النوع char فتَحتلّ مساحة ٢ بايت من الذاكرة، وتَحمِل محرفًا وحيدًا مثل "A" أو "*" أو "x" أو مسافة فارغة (space) أو محرفًا خاصًا مثل المحرف "tab" أو محرف "العودة إلى بداية السطر (carriage return)" أو إحدى محارف اليونيكود (Unicode character) بلغات مختلفة. يَستخدِم النوع char ترميزًا عدديًا صحيحًا (integer code number) مُكوَّن من ١٦ بت لتمثيل أي محرف، لذلك فإنه قيمه تُعدّ مرتبطة نوعًا ما بقيم الأعداد الصحيحة (integer)، وسنرى لاحقًا أنه يُمكِننا حتى اِستخدَامها كما لو كانت أعدادًا صحيحة بمواقف معينة.

لمّا كان الحاسوب يَستخدِم عددًا مُحدّدًا ومُتناهيًا (finite) من البتات لتمثيل قيمة أي نوع أساسي (primitive type)، فلا يُمكِن إذًا لقيم النوع int أن تُمثِل أي عدد صحيح عشوائي بل لابُدّ أن يَقَع العََدَد الصحيح ضِمْن نطاق مُحدّد ومُتناهي من القيم. بالمثل، يُمكِن للمُتْغيِّرات من النوعين float و double أن تَحمِل قيمًا محددة فقط أي أنها ليست أعدادًا حقيقية فعليًا بالمفهوم الرياضي. فمثلًا، لأن الثابت الرياضي π يَتَطلّب عددًا لامُتناهيًا من الأرقام العشرية لتمثيله، فلابُدّ من تقريبه أولًا قبل تَخْزِينه بمُتْغيِّر من النوع float أو النوع double. بالمثل، لابُدّ من تقريب الأعداد البسيطة مثل 1/3 قبل تَخْزِينها بمُتْغيِّرات من النوع float و double.

القيم مصنَّفة النوع (literals)

تُخزَّن أي بيانات بالحاسوب كمتتالية من البتات (bits). بالنسبة للقيم الثابتة (constant values)، فإنها تُمثَل باستخدَام ما يُعرَف باسم "القيم مُصنَّفة النوع (literals)"، والتي هي عبارة عن شيء يُمكِنك كتابته لتمثيل قيمة أي يُمكِن عدّه اسمًا لقيمة ثابتة.

لكتابة قيمة من النوع char على سبيل المثال، لابُدّ من إحاطتها بعلامتي اقتباس مُفرّدتين مثل 'A' و '*' و 'x'. يُشكِّل المحرف وعلامتي الاقتباس معًا "قيمة مُصنَّفة النوع (literal)" من النوع char. بدون علامتي الاقتباس، سيُمثِل A مُعرّفًا (identifier) أما * فستُمثِل عامل حاصل الضرب (multiplication operator). إذا كنت تريد أن تُخزِّن المحرف A بمُتْغيِّر ch من النوع char، فيُمكِنك أن تَستخدِم تَعْليمَة الإِسناد (assignment statement) التالية. لا تُعدّ علامتي الاقتباس جزءًا من القيمة ولا تُخزَّن بالمُتْغيِّر (variable)، فهي فقط نَمْط لتسمية الثوابت المحرفية (character constant):

ch = 'A';

تَستخدِم بعض المحارف الخاصة قيمًا خاصة مُصنَّفة النوع (literals) تَتَضمَّن خطًا مائلًا عكسيًا (backslash) يَعمَل كمحرف هروب (escape character)، فمثلًا، يُمثِل '‎\t' المحرف "tab"، ويُمثِل '‎\r' محرف العودة إلى بداية السطر (carriage return)، ويُمثِل '‎\n' محرف إضافة سطر جديد، ويُمثِل ''\' علامة اقتباس مُفردة، ويُمثِل '‎\\' محرف خط مائل عكسي (backslash). يَتَكوَّن كُلًا منها من محرفين إلى جانب علامتي الاقتباس، ومع ذلك فإنه يُشير إلى محرف واحد فقط، فمثلًا تُشير القيمة مُصنَّفة النوع '‎\t' إلى محرف "tab" واحد فقط.

قد تَكُون القيم العَدَدية مُصنَّفة النوع (Numeric literals) أعقد قليلًا مما تَتَوقَّع. هنالك بالطبع أمثلة واضحة مثل 317 و 17.42، ولكن هنالك احتمالات وطرائق أخرى لتمثيل الأعداد بلغة الجافا. أولًا، قد تُستخدَم صيغة أُسية (exponential form) لتمثيل الأعداد الحقيقية مثل 1.3e12 أو 12.3737e-108 حيث "e12" و "e-108" هي أسس للعدد ١٠ أي يُكافئ العدد 1.3e12 حاصل ضرب ١,٣ في ١٢١٠‏‏ أما العدد 12.3737e-108 فيُكافئ حاصل ضرب ١٢,٣٧٣٧ في ‎١٠-١٠٨. عادةً ما تُستخدَم هذه الصيغة للتعبير عن الأعداد الصغيرة جدًا أو الكبيرة جدًا. ثانيًا، قد تحتوي بعض القيم العددية مُصنَّفة النوع (numeric literal) على علامة عشرية (decimal point) أو على أس (exponential)، وتُعدّ عندها قيمًا من النوع double أتوماتيكيًا أما إذا أردت أن تُنشِيء قيمة مُصنَّفة من النوع float، فينبغي أن تضيف الحرف "f" أو "F" إلى نهاية العدد، فتُمثِل "1.2F" مثلًا قيمة من النوع float تُساوِي 1.2. ولأن الجافا لا تَسمَح بإسناد (assign) قيمة من النوع double لمُتْغيِّر من النوع float، فستُواجهك رسالة خطأ سخيفة نوعًا ما إذا حاولت أن تقوم بشيء مثل x = 1.2;‎ عندما يَكُون x مُتْغيِّر من النوع float، وعندها يَنبغي أن تُضيف الحرف "F" بالنهاية كالتالي x = 1.2F;‎. حاول عمومًا أن تَستخدِم النوع double لتمثيل الأعداد الحقيقية بالبرامج الخاصة بك.

أما بالنسبة لقيم الأعداد الصحيحة مُصنَّفة النوع (integer literals)، فهنالك أعداد صحيحة عادية مثل 177777 و ‎-32 والتي إما أن تَكُون من النوع byte أو النوع short أو النوع int بحسب حجمها. في المقابل، يُمكِنك أن تُنشِيء قيمة مُصنَّفة النوع (literal) من النوع long بإضافة الحرف "L" بنهاية العدد مثل 17L أو 728476874368L. تَسمَح الجافا أيضًا باستخدام قيم عددية ثنائية (binary) أو ثُمانيّة (octal) أو ست عشريّة (hexadecimal) مُصنَّفة النوع. لن نناقش أيًا منها على نحو تفصيلي وإنما سنَكتفِي بالنقاط التالية: أولًا، تَقْتصِر الأعداد الثُمانيّة (octal numbers) على الأرقام العشرية من ٠ إلى ٧ فقط، وتبدأ أي قيمة ثُمانيّة مُصنَّفة النوع (octal literal) بصفر مثل القيمة 045 والتي تُمثِل العدد 37 وليس العدد 45. نادرًا ما تُستخدَم الأعداد الثُمانيّة ومع ذلك تذكَّر على الأقل أنها تبدأ بصفر. ثانيًا، تَتَكوَّن الأعداد الست عشرية (Hexadecimal numbers) من ‏١٦ رقم هي الأرقام العشريّة العادية من ٠ إلى ٩ بالإضافة إلى الحروف A و B و C و D و E و F وبحيث تُمثِل تلك الحروف القيم من ١٠ إلى ١٥ على التوالي. لاحِظ أن الحروف الصغيرة (lower case letters) من a وحتى f لها نفس قيمة نظيراتها من الحروف الكبيرة (upper case). تبدأ القيم الست عشرية مُصنَّفة النوع (hexadecimal literal) بالجافا باستخدام 0x أو 0X مثل 0x45 أو 0xFF7A. وأخيرًا، تبدأ القيم الثنائية مُصنَّفة النوع (binary literals) باستخدام 0b أو 0B، وتَتَكوَّن من الرقمين ٠ و ١ فقط مثل 0b10110.

قد تحتوي القيم العددية مُصنَّفة النوع (numeric literals) على محرف شرطة سفلية (underscores) "_" لفَصْل مجموعات الأرقام (digits) عن بعضها وبدون أي قاعدة فيما يَتَعلَّق بعَدَد الأرقام ضِمْن كل مجموعة. يُمكِننا مثلًا كتابة الثابت العددي ٢ بليون بهيئة ‎2_000_000_000 بدلًا من 2000000000 مما يُسهِل من قراءة العدد. تَبرُز أهمية الشُرَط السفليّة على نحو أكبر عند اِستخدَامها بالأعداد الثنائية (binary numbers) الطويلة مثل 0b1010_1100_1011.

تُستخدَم الأعداد الست عشرية (hexadecimal numbers) أيضًا كقيم محرفية مُصنَّفة النوع (character literals) لتمثيل بعض محارف اليونيكود (unicode characters). تَتَكوَّن أي قيمة يونيكود مُصنَّفة النوع (unicode literal) من ‎\u متبوعة بأربعة أرقام ست عشريّة. تُمثِل مثلًا القيمة المحرفية مُصنَّفة النوع '‎\u00E9' محرف يونيكود هو الحرف "é".

أخيرًا، بالنسبة للنوع boolean، فتُستخدَم القيمتين true و false كقيم مُصنَّفة النوع (literal)، وتُكْتَب على نفس هذه الهيئة بدون علامتي اقتباس مع أنها تُمثِل قيم لا مُتْغيِّرات (variables). عادةً ما تُستخدَم القيم المنطقية كقيم للتعبيرات الشرطية (conditional expressions) كالمثال التالي:

rate > 0.05

يُعيد التعبير المنطقي (boolean-valued expressions) السابق قيمة إما تُساوِي true إذا كانت قيمة المُتْغيِّر rate أكبر من 0.05 أو تُساوِي false إذا كنت قيمته أقل من أو تُساوِي 0.05. تُستخدَم التعبيرات المنطقية بكثرة ضِمْن بُنى التَحكُّم (control structure) كما سنرى بالفصل الثالث. إلى جانب ذلك، يُمكِننا أيضًا أن نُسنِد القيم المنطقية إلى مُتْغيِّرات من النوع boolean. فمثلًا إذا كان test مُتْغيِّرًا من النوع boolean فيُمكننا كتابة تَعْليمَتي الإِسْناد (assignment statement) التاليتين:

test = true;
test = rate > 0.05;

السلاسل النصية (strings) والسلاسل النصية المجردة (string literals)

إلى جانب الأنواع الأساسية (primitive types)، تُوفِّر الجافا أنواعًا آخرى قيمها عبارة عن كائنات (objects) وليس قيم أساسية (primitive). ليس هذا وقتًا مناسبًا بالطبع للحديث عن الكائنات (objects)، ولكننا مُضطرّون للحديث عن النوع String لأهميته. هو ببساطة نوع كائني (object type) مُعرَّف مُسْبَقًا تُوفِّره الجافا لتمثيل السَلاسِل النصية (strings). لا يَقَع ذلك النوع ضِمْن الأنواع الأساسية (primitive)، بل هو في الواقع اسم صَنْف (class)، وهو ما سنعود للحديث عنه بالقسم التالي.

تَتَكوَّن القيم من النوع String من متتالية من المحارف مثل السِلسِلة النصية المُجرّدة "Hello World!‎" التي تَعرَضنا لها بقسم سابق. لابُدّ من إحاطة النص بعلامتي اقتباس مزدوجتين حيث تُعدّ كلتاهما جزءًا من السِلسِلة النصية المجرّدة (string literal)، ولكنهما مع ذلك ليسا جزءًا من قيمتها الفعليّة والتي تَقْتصِر على المحارف بين علامتي الاقتباس. قد تحتوي السِلسِلة النصية من النوع String على أي عدد من المحارف بما في ذلك الصفر، وعندها تَكُون بمثابة سِلسِلة نصية فارغة (empty string) تُمثَل بالسِلسِلة النصية المُجرّدة "" أي مُكوَّنة من علامتي اقتباس مزدوجتين فارغتين. انتبه جيدًا للفارق بين علامتي اقتباس فرديتين وآخريتين مزدوجتين حيث تُستخدَم الأولى مع القيم المحرفية مُصنَّفة النوع (char literals) أما الثانية فتُستخدَم مع السَلاسِل النصية المُجرّدة (String literals)، فمثلًا، لاحظ الفرق بين السِلسِلة النصية "A" والحرف 'A'.

قد تَتَضمَّن السَلاسِل النصية المُجرّدة (string literal) محارفًا خاصة، ويُستخدم عندها خطًا مائلًا عكسيًا (backslash) لتمثيلها. ضِمْن هذا السياق، تُعدّ علامة الاقتباس المزدوجة محرفًا خاصًا، فإذا كان لدينا القيمة النصية التالية (string value):

I said, "Are you listening!"

يُمكِننا إذًا تمثيلها باستخدام سِلسِلة نصية مُجرّدة (string literal) كالتالي مع محرف "إضافة سطر جديد (linefeed)" بالنهاية:

"I said, \"Are you listening!\"\n"

يُمكِنك أيضًا أن تَستخدِم ‎\t و ‎\r و \\ وكذلك متتاليات اليونيكود مثل ‎\u00E9 لتمثيل محارف خاصة آخرى ضمن السِلاسِل النصية المُجرّدة (string literals).

المتغيرات بالبرامج

ينبغي دائمًا أن تُصرِّح (declare) عن أي مُتْغيِّر (variable) قبل اِستخدَامه. تُستخدَم تَعْليمَة التَصْرِيح عن المُتْغيِّرات (variable declaration statement) للإعلان عن مُتْغيِّر واحد أو أكثر وكذلك تَخْصيص اسم لكُلًا منها. عندما يُنفِّذ الحاسوب تَعْليمَة تَصْرِيح عن مُتْغيِّر، فإنه يَحجِز له مساحة من الذاكرة كما يَربُط اسمه بتلك المساحة. تُكْتَب تَعْليمَة التَصْريح عن مُتْغيِّر بالصياغة التالية:

<type-name>  <variable-name-or-names>;

تُمثِل اسم مُتْغيِّر واحد أو قائمة من أسماء المُتْغيِّرات يَفصِل بينها فاصلة (comma). يُمكِن لتَعْليمَات التَصْرِيح عن المُتْغيِّرات أن تَكُون أكثر تعقيدًا من ذلك كما سنرى لاحقًا. يُفضَّل عمومًا التَصْرِيح (declare) عن مُتْغيِّر واحد فقط بكل تَعْليمَة تَصْرِيح (declaration statement) إلا لو كانت تلك المُتْغيِّرات مُرتبطَة ببعضها. اُنظر الأمثلة التالية:

int numberOfStudents;
String name;
double x, y;        
boolean isFinished;
char firstInitial, middleInitial, lastInitial;

يُفضَّل أيضًا إضافة بعض التعليقات (comment) لكل تَعْليمَة تَصْرِيح عن مُتْغيِّر (variable declaration)؛ لشرح غرضه بالبرنامج أو لتَوفِير بعض المعلومات التي يُمكِنها أن تُساعِد أي مبرمج آخر يَرغَب بقراءة البرنامج. اُنظر الأمثلة التالية:

double principal;    // مقدار النقود المُستثمَرَ
double interestRate; // معدل الفائدة كقيمة وليس نسبة

بهذا الفصل، سنَستخدِم المُتْغيِّرات (variables) المُصرَّح (declare) عنها داخل البرنامج الفرعي main()‎ فقط. تُعرَف المُتغيرات المُصرَّح عنها داخل برنامج فرعي (subroutine) معين باسم "المُتْغيِّرات المحليّة (local)" وتَكُون مُتوفِّرة فقط داخل ذلك البرنامج الفرعي عند تَشْغِيله ولا يُمكِن الوصول إليها من خارجه نهائيًا. يُمكِنك أن تُصرِّح عن مُتْغيِّرات بأي مكان داخل البرنامج الفرعي بشَّرْط ألا تَستخدِم أبدًا مُتْغيِّر معين بدون أن تُصرِّح عنه أولًا. يُفضِّل بعض الأشخاص التَصْريح (declare) عن جميع المُتْغيِّرات ببداية البرنامج الفرعي بينما يُفضِّل آخرون إرجاء التَصْرِيح عن المُتْغيِّرات إلى حين الحاجة لاِستخدَامها مباشرةً. يُفضِّل الكاتب التَصْرِيح عن المُتْغيِّرات الهامة والمحورية ببداية البرنامج الفرعي مع إضافة تعليق (comment) على كل تَعْليمَة تَصْرِيح منها يشرح الغرض من المُتْغيِّر، وفي المقابل يرى الكاتب أنه من الممكن إرجاء التَصْرِيح عن المُتْغيِّرات غَيْر المُهِمّة إلى حين الحاجة لاِستخدَامها لأول مرة. يَستخدِم البرنامج التالي بعض المُتْغيِّرات (variables) وتَعْليمَات الإِسْناد (assignment statements):

public class Interest {

   public static void main(String[] args) {

       /* صرح عن المتغيرات */

       double principal;     // قيمة الاستثمار
       double rate;          // معدل الفائدة السنوي
       double interest;      // قيمة معدل الفائدة بعام واحد

       /* إحسب القيم المطلوبة */

       principal = 17000;
       rate = 0.027;
       interest = principal * rate;   // احسب معدل الفائدة

       principal = principal + interest;
             // احسب قيمة الاستثمار بعد عام واحد مع الفائدة

       /* اعرض النتائج */

       System.out.print("The interest earned is $");
       System.out.println(interest);
       System.out.print("The value of the investment after one year is $");
       System.out.println(principal);

   } // ‫نهاية main()

} // ‫نهاية الصنف Interest

يَستدعِي البرنامج بالأعلى مجموعة من البرامج الفرعية (subroutine call) مثل System.out.print و System.out.println لعَرْض بعض المعلومات للمُستخدِم. بخلاف البرنامج الفرعي الأول، يَطبَع البرنامج الثاني محرف "إضافة سطر جديد (linefeed)" بَعْد عَرْض المعلومة ذاتها، فمثلًا، تَطبَع تَعْليمَة الاستدعاء System.out.println(interest);‎ قيمة المُتْغيِّر interest بنفس سطر السِلسِلة النصية المعروضة بواسطة تَعْليمَة الاستدعاء System.out.print السابقة. يُفْترَض للقيمة المطلوب طباعتها باِستخدَام System.out.print أو System.out.println أن تُكْتَب بَعْد اسم البرنامج الفرعي (subroutine) داخل أقواس ويُطلق عليها اسم المُعامِل (parameter). قد يَستقبِل أي برنامج فرعي معاملًا واحدًا أو أكثر لتوفير بعض المعلومات التي يَحتاج إليها ليُنفِّذ المُهِمّة المُوكَلة إليه. تُكْتَب تلك المُعامِلات (parameters) عند استدعاء البرنامج الفرعي (subroutine call) بَعْد اسمه داخل أقواس. في المقابل، قد لا يَستقبِل برنامج فرعي (subroutine) أي مُعامِلات، وفي تلك الحالة لابُدّ أن يُكْتَب زوج من الأقواس الفارغة بَعْد اسم البرنامج الفرعي بتَعْليمَة استدعائه.

ملحوظة: جميع ملفات الشيفرة المصدرية (source code) للأمثلة التوضيحية بالكتاب متاحة بنسخة الكتاب المتوفرة عبر الانترنت كما أنها مُضمَّنة بمجلد اسمه "source" بالنسخة الأرشيفية لموقع الإنترنت. يمكنك مثلًا العثور على ملف الشيفرة المصدرية للبرنامج Interest بالملف Interest.java الموجود بمجلد فرعي اسمه "chapter2" داخل المجلد "source".

ترجمة -بتصرّف- للقسم Section 2: Variables and the Primitive Types من فصل Chapter 2: Programming in the Small I: Names and Things من كتاب Introduction to Programming Using Java.


تفاعل الأعضاء

أفضل التعليقات

اقتباس

 هل يُمكِننا ببساطة أن نَدعِي أننا قد ضربنا principal بالقيمة 0.07؟ في الواقع لا! لأن قيمة rate قد تَتَغيَّر في أي لحظة بواسطة تَعْليمَة إِسناد آخرى.

في حالة

interest = rate * principal;

لنفترض أنا وضعنا بعدها rate = 4 ستبقى قيمى interest نفسها , فلم أفهم لما الإدعاء هذا خاطئ , قد يقال نعم ليس بالضرورة أننا ضربنا interest ب0.007 لأن rate قد تكون مجهولة القيمة بالنسبة لنا

رابط هذا التعليق
شارك على الشبكات الإجتماعية

بتاريخ On 10/8/2021 at 06:48 قال اسماعيل Ismail:

في حالة

interest = rate * principal;

لنفترض أنا وضعنا بعدها rate = 4 ستبقى قيمى interest نفسها , فلم أفهم لما الإدعاء هذا خاطئ , قد يقال نعم ليس بالضرورة أننا ضربنا interest ب0.007 لأن rate قد تكون مجهولة القيمة بالنسبة لنا

المقصود هنا تبسيط لفكرة المتغير, ما تريد أن توصله الأستاذة رضوى, أن rate ليس رقم أو عدد, وإنما متغير قد يحمل أي قيمة في أي لحظة , فالأصح أن ﻻ نقول إننا ضربنا الinterest في 0.07, بل أن نقول أننا ضربنا الinterest  في قيمة الrate والتي كانت في لحظة الضرب تحمل القيمة 0.07, الموضوع أشبه بحملك لحقيبة تحتوي على مﻻبس ويسألك شخصاً ما عن ما بيدك فتُخبره أنها حقيبة, من الممكن أن تخبره أنها حقيبة تحتوي على مﻻبس, ولكن ليس من المﻻئم إخباره أن ما بيدك "مﻻبس" وإنما هي حقيبة تحتوي على المﻻبس

رابط هذا التعليق
شارك على الشبكات الإجتماعية

بتاريخ منذ ساعة مضت قال شرف الدين2:

المقصود هنا تبسيط لفكرة المتغير, ما تريد أن توصله الأستاذة رضوى, أن rate ليس رقم أو عدد, وإنما متغير قد يحمل أي قيمة في أي لحظة , فالأصح أن ﻻ نقول إننا ضربنا الinterest في 0.07, بل أن نقول أننا ضربنا الinterest  في قيمة الrate والتي كانت في لحظة الضرب تحمل القيمة 0.07, الموضوع أشبه بحملك لحقيبة تحتوي على مﻻبس ويسألك شخصاً ما عن ما بيدك فتُخبره أنها حقيبة, من الممكن أن تخبره أنها حقيبة تحتوي على مﻻبس, ولكن ليس من المﻻئم إخباره أن ما بيدك "مﻻبس" وإنما هي حقيبة تحتوي على المﻻبس

تمام وصلت الفكرة

شكرا 

رابط هذا التعليق
شارك على الشبكات الإجتماعية



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...